Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 89 additions & 65 deletions rust/src/chrome.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const CFT_MACOS_APP_NAME: &str =
"Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing";
const MIN_CHROME_VERSION_CFT: i32 = 113;
const MIN_CHROMEDRIVER_VERSION_CFT: i32 = 115;
const MIN_CHROME_VERSION_LINUX_ARM64: i32 = 153;
const CHROMIUM_SNAP_LINK: &str = "/snap/bin/chromium";
const CHROMIUM_SNAP_BINARY: &str = "/snap/chromium/current/usr/lib/chromium-browser/chrome";

Expand Down Expand Up @@ -132,6 +133,23 @@ impl ChromeManager {
self.create_cft_url(&self.get_driver_mirror_url_or_default(CFT_URL), endpoint)
}

fn find_platform_url<'a>(&self, downloads: &'a [PlatformUrl]) -> Option<&'a str> {
downloads
.iter()
.find(|p| p.platform.eq_ignore_ascii_case(self.get_platform_label()))
Comment thread
titusfortner marked this conversation as resolved.
.map(|p| p.url.as_str())
}

// CfT publishes Linux arm64 binaries later than the rest of the platforms, so the minimum
// version available for download is higher there than the general CfT minimum.
fn min_version_for_platform(&self, min_cft_version: i32) -> i32 {
if LINUX.is(self.get_os()) && ARM64.is(self.get_arch()) {
MIN_CHROME_VERSION_LINUX_ARM64.max(min_cft_version)
} else {
min_cft_version
}
}

fn request_driver_version_from_latest(&self, driver_url: &str) -> Result<String, Error> {
self.log.debug(format!(
"Reading {} version from {}",
Expand Down Expand Up @@ -169,18 +187,16 @@ impl ChromeManager {
return self.request_driver_version_from_latest(&self.create_latest_release_url());
}

let platform_url: Vec<&PlatformUrl> = chromedriver
.as_ref()
.unwrap()
.iter()
.filter(|p| p.platform.eq_ignore_ascii_case(self.get_platform_label()))
.collect();
let platform_url = self.find_platform_url(chromedriver.as_ref().unwrap());
self.log.trace(format!(
"CfT URLs for downloading {}: {:?}",
"CfT URL for downloading {}: {:?}",
self.get_driver_name(),
platform_url
));
self.driver_url = Some(platform_url.first().unwrap().url.to_string());
match platform_url {
Some(url) => self.driver_url = Some(url.to_string()),
None => return self.unavailable_discovery(),
}

Ok(stable_channel.version)
}
Expand All @@ -203,10 +219,19 @@ impl ChromeManager {
let good_versions_url = self.create_cft_url_for_drivers(GOOD_VERSIONS_ENDPOINT);
let all_versions =
self.request_versions_from_online::<VersionsWithDownloads>(&good_versions_url)?;
// Not every version is published for every platform, so the availability of a download
// for the current platform is part of the filter (and not a later check) to let the most
// recent usable version win
let filtered_versions: Vec<Version> = all_versions
.versions
.into_iter()
.filter(|r| r.version.starts_with(version_for_filtering.as_str()))
.filter(|r| {
r.version.starts_with(version_for_filtering.as_str())
&& r.downloads
.chromedriver
.as_deref()
.is_some_and(|d| self.find_platform_url(d).is_some())
})
.collect();
if filtered_versions.is_empty() {
return Err(anyhow!(format!(
Expand All @@ -216,23 +241,25 @@ impl ChromeManager {
self.get_driver_name(),
version_for_filtering.as_str(),
self.get_arch(),
&MIN_CHROMEDRIVER_VERSION_CFT.to_string(),
&self
.min_version_for_platform(MIN_CHROMEDRIVER_VERSION_CFT)
.to_string(),
),
CFT_URL
)));
}

let driver_version = filtered_versions.last().unwrap();
let url: Vec<&PlatformUrl> = driver_version
let url = driver_version
.downloads
.chromedriver
.as_ref()
.unwrap()
.iter()
.filter(|p| p.platform.eq_ignore_ascii_case(self.get_platform_label()))
.collect();
self.log.trace(format!("URLs for CfT: {:?}", url));
self.driver_url = Some(url.first().unwrap().url.to_string());
.as_deref()
.and_then(|d| self.find_platform_url(d));
self.log.trace(format!("URL for CfT: {:?}", url));
match url {
Some(url) => self.driver_url = Some(url.to_string()),
None => return self.unavailable_discovery(),
}

Ok(driver_version.version.to_string())
}
Expand Down Expand Up @@ -420,9 +447,12 @@ impl SeleniumManager for ChromeManager {
"mac64"
}
} else if LINUX.is(os) && ARM64.is(arch) {
return Err(anyhow!(
"Linux arm64 is not supported yet by Google Chrome. Please try another browser."
));
// This URL scheme only serves chromedriver 114-, which was never published for Linux
// arm64. Newer versions are served by the CfT endpoints and never reach this point.
return Err(anyhow!(format!(
"Linux arm64 requires {} {} or above",
self.driver_name, MIN_CHROME_VERSION_LINUX_ARM64
)));
} else {
"linux64"
};
Expand Down Expand Up @@ -484,6 +514,8 @@ impl SeleniumManager for ChromeManager {
} else {
"mac-x64"
}
} else if ARM64.is(arch) {
"linux-arm64"
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
} else {
"linux64"
}
Expand All @@ -494,14 +526,6 @@ impl SeleniumManager for ChromeManager {
_browser_version: &str,
) -> Result<String, Error> {
let browser_name = self.browser_name;
let os = self.get_os();
let arch = self.get_arch();
if LINUX.is(os) && ARM64.is(arch) {
return Err(anyhow!(format!(
"Linux arm64 is not supported yet by {}. Please try another browser.",
browser_name
)));
}
self.get_logger().trace(format!(
"Using Chrome for Testing (CfT) endpoints to find out latest stable {} version",
browser_name
Expand All @@ -511,29 +535,27 @@ impl SeleniumManager for ChromeManager {
let versions_with_downloads =
self.request_versions_from_online::<LatestVersionsWithDownloads>(&latest_versions_url)?;
let stable_channel = versions_with_downloads.channels.stable;
let chrome = stable_channel.downloads.chrome;

let platform_url: Vec<&PlatformUrl> = chrome
.iter()
.filter(|p| p.platform.eq_ignore_ascii_case(self.get_platform_label()))
.collect();
let platform_url = self.find_platform_url(&stable_channel.downloads.chrome);
self.log.trace(format!(
"CfT URLs for downloading {}: {:?}",
"CfT URL for downloading {}: {:?}",
self.get_browser_name(),
platform_url
));
let browser_version = stable_channel.version;
self.browser_url = Some(platform_url.first().unwrap().url.to_string());
match platform_url {
Some(url) => self.browser_url = Some(url.to_string()),
None => return self.unavailable_discovery(),
}

Ok(browser_version)
Ok(stable_channel.version)
}

fn request_fixed_browser_version_from_online(
&mut self,
_browser_version: &str,
) -> Result<String, Error> {
let browser_name = self.browser_name;
let mut browser_version = self.get_browser_version().to_string();
let browser_version = self.get_browser_version().to_string();
let major_browser_version = self.get_major_browser_version();
self.get_logger().trace(format!(
"Using Chrome for Testing (CfT) endpoints to find out {} {}",
Expand All @@ -553,48 +575,50 @@ impl SeleniumManager for ChromeManager {
} else {
versions_with_downloads.channels.canary
};
browser_version = channel.version;
let platform_url: Vec<&PlatformUrl> = channel
.downloads
.chrome
.iter()
.filter(|p| p.platform.eq_ignore_ascii_case(self.get_platform_label()))
.collect();
self.browser_url = Some(platform_url.first().unwrap().url.to_string());
let platform_url = self.find_platform_url(&channel.downloads.chrome);
match platform_url {
Some(url) => self.browser_url = Some(url.to_string()),
None => return self.unavailable_discovery(),
}

Ok(browser_version)
Ok(channel.version)
} else {
let good_versions_url = self.create_cft_url_for_browsers(GOOD_VERSIONS_ENDPOINT);
let all_versions =
self.request_versions_from_online::<VersionsWithDownloads>(&good_versions_url)?;
let iter_versions = all_versions.versions.into_iter();
let filtered_versions: Vec<Version> = if self.is_browser_version_specific() {
iter_versions
.filter(|r| r.version.eq(browser_version.as_str()))
.collect()
} else {
iter_versions
.filter(|r| r.version.starts_with(major_browser_version.as_str()))
.collect()
let version_matches = |r: &Version| {
if self.is_browser_version_specific() {
r.version.eq(browser_version.as_str())
} else {
r.version.starts_with(major_browser_version.as_str())
}
};
// Not every version is published for every platform, so the availability of a download
// for the current platform is part of the filter (and not a later check) to let the
// most recent usable version win
let filtered_versions: Vec<Version> = all_versions
.versions
.into_iter()
.filter(|r| {
version_matches(r) && self.find_platform_url(&r.downloads.chrome).is_some()
})
.collect();
if filtered_versions.is_empty() {
return self.unavailable_download();
}
let last_browser = filtered_versions.last().unwrap();
let platform_url: Vec<&PlatformUrl> = last_browser
.downloads
.chrome
.iter()
.filter(|p| p.platform.eq_ignore_ascii_case(self.get_platform_label()))
.collect();
self.browser_url = Some(platform_url.first().unwrap().url.to_string());
let platform_url = self.find_platform_url(&last_browser.downloads.chrome);
match platform_url {
Some(url) => self.browser_url = Some(url.to_string()),
None => return self.unavailable_discovery(),
}

Ok(last_browser.version.to_string())
}
}

fn get_min_browser_version_for_download(&self) -> Result<i32, Error> {
Ok(MIN_CHROME_VERSION_CFT)
Ok(self.min_version_for_platform(MIN_CHROME_VERSION_CFT))
}

fn get_browser_binary_path(&mut self, _browser_version: &str) -> Result<PathBuf, Error> {
Expand Down
5 changes: 3 additions & 2 deletions rust/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,9 @@ impl ARCH {
match self {
ARCH::X32 => vec![ARCH_X86, "i386", "x32", "i686"],
ARCH::X64 => vec![ARCH_X64, "amd64", "x64", "ia64"],
ARCH::ARM64 => vec![ARCH_ARM64, "aarch64", "arm"],
ARCH::ARMV7 => vec![ARCH_ARM7L, "armv7l"],
ARCH::ARM64 => vec![ARCH_ARM64, "aarch64"],
// "arm" is the conventional name for 32-bit ARM (e.g. std::env::consts::ARCH)
ARCH::ARMV7 => vec![ARCH_ARM7L, "armv7l", "arm"],
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
}
}

Expand Down
19 changes: 9 additions & 10 deletions rust/tests/browser_download_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
// specific language governing permissions and limitations
// under the License.

use crate::common::is_linux_arm64;
use crate::common::{assert_browser, assert_driver, get_selenium_manager};

use rstest::rstest;
use std::env::consts::ARCH;
use std::env::consts::OS;

mod common;
Expand All @@ -30,7 +30,7 @@ mod common;
fn browser_latest_download_test(#[case] browser: String) {
if browser.eq("edge") && OS.eq("windows") {
return;
} else if OS.eq("linux") && ARCH.eq("aarch64") && !browser.eq("firefox") {
} else if is_linux_arm64() && browser.eq("edge") {
return;
}

Expand All @@ -54,6 +54,7 @@ fn browser_latest_download_test(#[case] browser: String) {
#[rstest]
#[case("chrome", "131")]
#[case("chrome", "131.0.6778.264")]
#[case("chrome", "153")]
#[case("chrome", "beta")]
#[case("firefox", "121")]
#[case("firefox", "121.0.1")]
Expand All @@ -66,17 +67,15 @@ fn browser_version_download_test(#[case] browser: String, #[case] browser_versio
println!(
"Skipping Edge download test on Windows since the installation requires admin privileges"
);
} else if OS.eq("linux") && ARCH.eq("aarch64") && !browser.eq("firefox") {
} else if is_linux_arm64() && browser.eq("edge") {
println!("Skipping Edge download test on Linux arm64 since it's not supported yet");
} else if is_linux_arm64() && browser.eq("firefox") && browser_version.starts_with("121") {
println!(
"Skipping non-Firefox download test on Linux arm64 since no other browsers are supported yet"
"Skipping Firefox 121 download test on Linux arm64 since arm64 builds are only available from version 136 onwards"
);
} else if OS.eq("linux")
&& ARCH.eq("aarch64")
&& browser.eq("firefox")
&& browser_version.starts_with("121")
{
} else if is_linux_arm64() && browser.eq("chrome") && browser_version.starts_with("131") {
println!(
"Skipping Firefox 121 download test on Linux arm64 since arm64 builds are only available from version 136 onwards"
"Skipping Chrome 131 download test on Linux arm64 since arm64 builds are only available from version 153 onwards"
);
} else {
let mut cmd = get_selenium_manager();
Expand Down
Loading