wasm_pack/test/webdriver/
chromedriver.rs1use super::get_and_notify;
2use crate::install::InstallMode;
3use crate::stamps;
4use crate::target;
5use anyhow::{bail, Context, Result};
6use binary_install::Cache;
7use chrono::DateTime;
8use std::collections::HashMap;
9use std::path::PathBuf;
10
11const DEFAULT_CHROMEDRIVER_VERSION: &str = "114.0.5735.90";
14
15const CHROMEDRIVER_LAST_UPDATED_STAMP: &str = "chromedriver_last_updated";
16const CHROMEDRIVER_VERSION_STAMP: &str = "chromedriver_version";
17
18pub fn get_or_install_chromedriver(cache: &Cache, mode: InstallMode) -> Result<PathBuf> {
21 if let Ok(path) = which::which("chromedriver") {
22 return Ok(path);
23 }
24 install_chromedriver(cache, mode.install_permitted())
25}
26
27pub fn install_chromedriver(cache: &Cache, installation_allowed: bool) -> Result<PathBuf> {
29 let target = if target::LINUX && target::x86_64 {
30 "linux64"
31 } else if target::MACOS && target::x86_64 {
32 "mac-x64"
33 } else if target::MACOS && target::aarch64 {
34 "mac-arm64"
35 } else if target::WINDOWS {
36 "win32"
37 } else {
38 bail!("chromedriver binaries are unavailable for this target")
39 };
40
41 let url = get_chromedriver_url(target);
42
43 match get_and_notify(cache, installation_allowed, "chromedriver", &url)? {
44 Some(path) => Ok(path),
45 None => bail!(
46 "No cached `chromedriver` binary found, and could not find a global \
47 `chromedriver` on the `$PATH`. Not installing `chromedriver` because of noinstall \
48 mode."
49 ),
50 }
51}
52
53fn get_chromedriver_url(target: &str) -> String {
72 let fetch_and_save_version =
73 || fetch_chromedriver_version().and_then(save_chromedriver_version);
74
75 let chromedriver_version = match stamps::read_stamps_file_to_json() {
76 Ok(json) => {
77 if should_load_chromedriver_version_from_stamp(&json) {
78 stamps::get_stamp_value(CHROMEDRIVER_VERSION_STAMP, &json)
79 } else {
80 fetch_and_save_version()
81 }
82 }
83 Err(_) => fetch_and_save_version(),
84 }
85 .unwrap_or_else(|error| {
86 log::warn!(
87 "Cannot load or fetch chromedriver's latest version data, \
88 the default version {} will be used. Error: {}",
89 DEFAULT_CHROMEDRIVER_VERSION,
90 error
91 );
92 DEFAULT_CHROMEDRIVER_VERSION.to_owned()
93 });
94 assemble_chromedriver_url(&chromedriver_version, target)
95}
96
97fn save_chromedriver_version(version: String) -> Result<String> {
100 stamps::save_stamp_value(CHROMEDRIVER_VERSION_STAMP, &version)?;
101
102 let current_time = chrono::offset::Local::now().to_rfc3339();
103 stamps::save_stamp_value(CHROMEDRIVER_LAST_UPDATED_STAMP, current_time)?;
104
105 Ok(version)
106}
107
108fn should_load_chromedriver_version_from_stamp(json: &serde_json::Value) -> bool {
109 let last_updated = stamps::get_stamp_value(CHROMEDRIVER_LAST_UPDATED_STAMP, json)
110 .ok()
111 .and_then(|last_updated| DateTime::parse_from_rfc3339(&last_updated).ok());
112
113 match last_updated {
114 None => false,
115 Some(last_updated) => {
116 let current_time = chrono::offset::Local::now();
117 current_time.signed_duration_since(last_updated).num_hours() < 24
118 }
119 }
120}
121
122#[derive(Deserialize)]
124struct ChannelInfo {
125 version: String,
126}
127
128#[derive(Deserialize)]
130struct GoodLatestVersions {
131 channels: HashMap<String, ChannelInfo>,
132}
133
134fn fetch_chromedriver_version() -> Result<String> {
137 let info: GoodLatestVersions = ureq::builder()
138 .try_proxy_from_env(true)
139 .build()
140 .get("https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions.json")
141 .call()
142 .context("fetching of chromedriver's LATEST_RELEASE failed")?
143 .into_json()
144 .context("converting chromedriver version response to GoodLatestVersions failed")?;
145
146 let version = info
147 .channels
148 .get("Stable")
149 .ok_or_else(|| anyhow::anyhow!("no Stable channel found in chromedriver version response"))?
150 .version
151 .clone();
152
153 println!("chromedriver version: {}", version);
154
155 Ok(version)
156}
157
158fn assemble_chromedriver_url(chromedriver_version: &str, target: &str) -> String {
159 format!(
160 "https://storage.googleapis.com/chrome-for-testing-public/{version}/{target}/chromedriver-{target}.zip",
161 version = chromedriver_version,
162 target = target,
163 )
164}