Skip to content

Commit 4173713

Browse files
authored
[rust] Offline mode in Selenium Manager (#11639) (#12373)
1 parent ca60c22 commit 4173713

File tree

10 files changed

+102
-11
lines changed

10 files changed

+102
-11
lines changed

rust/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ Options:
5151
Display DEBUG messages
5252
--trace
5353
Display TRACE messages
54+
--offline
55+
Offline mode (i.e., disabling network requests and downloads)
5456
-h, --help
5557
Print help
5658
-V, --version

rust/src/chrome.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use crate::metadata::{
3434
use crate::{
3535
create_http_client, format_one_arg, format_three_args, SeleniumManager, BETA,
3636
DASH_DASH_VERSION, DEV, ENV_LOCALAPPDATA, ENV_PROGRAM_FILES, ENV_PROGRAM_FILES_X86, NIGHTLY,
37-
REG_QUERY, REMOVE_X86, STABLE, WMIC_COMMAND, WMIC_COMMAND_ENV,
37+
OFFLINE_REQUEST_ERR_MSG, REG_QUERY, REMOVE_X86, STABLE, WMIC_COMMAND, WMIC_COMMAND_ENV,
3838
};
3939

4040
pub const CHROME_NAME: &str = "chrome";
@@ -319,6 +319,8 @@ impl SeleniumManager for ChromeManager {
319319
Ok(driver_version)
320320
}
321321
_ => {
322+
self.assert_online_or_err(OFFLINE_REQUEST_ERR_MSG)?;
323+
322324
let major_browser_version = browser_version.parse::<i32>().unwrap_or_default();
323325
let driver_version = if !browser_version.is_empty() && major_browser_version < 115 {
324326
// For old versions (chromedriver 114-), the traditional method should work:

rust/src/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub struct ManagerConfig {
4141
pub timeout: u64,
4242
pub browser_ttl: u64,
4343
pub driver_ttl: u64,
44+
pub offline: bool,
4445
}
4546

4647
impl ManagerConfig {
@@ -87,6 +88,7 @@ impl ManagerConfig {
8788
timeout: IntegerKey("timeout", REQUEST_TIMEOUT_SEC).get_value(),
8889
browser_ttl: IntegerKey("browser-ttl", TTL_BROWSERS_SEC).get_value(),
8990
driver_ttl: IntegerKey("driver-ttl", TTL_DRIVERS_SEC).get_value(),
91+
offline: BooleanKey("offline", false).get_value(),
9092
}
9193
}
9294
}

rust/src/edge.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::metadata::{
3131
use crate::{
3232
create_http_client, format_one_arg, format_three_args, Logger, SeleniumManager, BETA,
3333
DASH_DASH_VERSION, DEV, ENV_LOCALAPPDATA, ENV_PROGRAM_FILES, ENV_PROGRAM_FILES_X86, NIGHTLY,
34-
REG_QUERY, REMOVE_X86, STABLE, WMIC_COMMAND, WMIC_COMMAND_ENV,
34+
OFFLINE_REQUEST_ERR_MSG, REG_QUERY, REMOVE_X86, STABLE, WMIC_COMMAND, WMIC_COMMAND_ENV,
3535
};
3636

3737
pub const EDGE_NAMES: &[&str] = &["edge", "msedge", "microsoftedge"];
@@ -180,6 +180,8 @@ impl SeleniumManager for EdgeManager {
180180
Ok(driver_version)
181181
}
182182
_ => {
183+
self.assert_online_or_err(OFFLINE_REQUEST_ERR_MSG)?;
184+
183185
if browser_version.is_empty() {
184186
let latest_stable_url = format!("{}{}", DRIVER_URL, LATEST_STABLE);
185187
self.log.debug(format!(

rust/src/firefox.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::metadata::{
3131
use crate::{
3232
create_http_client, format_one_arg, format_three_args, format_two_args, Logger,
3333
SeleniumManager, BETA, DASH_VERSION, DEV, ENV_PROGRAM_FILES, ENV_PROGRAM_FILES_X86, NIGHTLY,
34-
REG_QUERY_FIND, REMOVE_X86, STABLE, WMIC_COMMAND, WMIC_COMMAND_ENV,
34+
OFFLINE_REQUEST_ERR_MSG, REG_QUERY_FIND, REMOVE_X86, STABLE, WMIC_COMMAND, WMIC_COMMAND_ENV,
3535
};
3636

3737
pub const FIREFOX_NAME: &str = "firefox";
@@ -178,6 +178,8 @@ impl SeleniumManager for FirefoxManager {
178178
Ok(driver_version)
179179
}
180180
_ => {
181+
self.assert_online_or_err(OFFLINE_REQUEST_ERR_MSG)?;
182+
181183
let latest_url = format!("{}{}", DRIVER_URL, LATEST_RELEASE);
182184
let driver_version =
183185
read_redirect_from_link(self.get_http_client(), latest_url, self.get_logger())?;

rust/src/grid.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ use std::path::PathBuf;
2424
use crate::files::{get_cache_folder, BrowserPath};
2525

2626
use crate::downloads::parse_json_from_url;
27-
use crate::{create_http_client, parse_version, Logger, SeleniumManager, SNAPSHOT};
27+
use crate::{
28+
create_http_client, parse_version, Logger, SeleniumManager, OFFLINE_REQUEST_ERR_MSG, SNAPSHOT,
29+
};
2830

2931
use crate::metadata::{
3032
create_driver_metadata, get_driver_version_from_metadata, get_metadata, write_metadata,
@@ -107,6 +109,8 @@ impl SeleniumManager for GridManager {
107109
Ok(driver_version)
108110
}
109111
_ => {
112+
self.assert_online_or_err(OFFLINE_REQUEST_ERR_MSG)?;
113+
110114
let selenium_releases = parse_json_from_url::<Vec<SeleniumRelease>>(
111115
self.get_http_client(),
112116
MIRROR_URL.to_string(),

rust/src/iexplorer.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use std::path::PathBuf;
2424
use crate::files::{compose_driver_path_in_cache, BrowserPath};
2525

2626
use crate::downloads::parse_json_from_url;
27-
use crate::{create_http_client, parse_version, Logger, SeleniumManager};
27+
use crate::{create_http_client, parse_version, Logger, SeleniumManager, OFFLINE_REQUEST_ERR_MSG};
2828

2929
use crate::metadata::{
3030
create_driver_metadata, get_driver_version_from_metadata, get_metadata, write_metadata,
@@ -110,6 +110,8 @@ impl SeleniumManager for IExplorerManager {
110110
Ok(driver_version)
111111
}
112112
_ => {
113+
self.assert_online_or_err(OFFLINE_REQUEST_ERR_MSG)?;
114+
113115
let selenium_releases = parse_json_from_url::<Vec<SeleniumRelease>>(
114116
self.get_http_client(),
115117
MIRROR_URL.to_string(),

rust/src/lib.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ pub const UNAME_COMMAND: &str = "uname -{}";
8888
pub const CRLF: &str = "\r\n";
8989
pub const LF: &str = "\n";
9090
pub const SNAPSHOT: &str = "SNAPSHOT";
91+
pub const OFFLINE_REQUEST_ERR_MSG: &str = "Unable to discover proper {} version in offline mode";
92+
pub const OFFLINE_DOWNLOAD_ERR_MSG: &str = "Unable to download {} in offline mode";
9193

9294
pub trait SeleniumManager {
9395
// ----------------------------------------------------------
@@ -382,6 +384,7 @@ pub trait SeleniumManager {
382384
}
383385
} else {
384386
// If driver is not in the cache, download it
387+
self.assert_online_or_err(OFFLINE_DOWNLOAD_ERR_MSG)?;
385388
self.download_driver()?;
386389
}
387390
Ok(driver_path)
@@ -424,6 +427,13 @@ pub trait SeleniumManager {
424427
Ok(format!("selenium-{release_version}"))
425428
}
426429

430+
fn assert_online_or_err(&self, message: &str) -> Result<(), Box<dyn Error>> {
431+
if self.is_offline() {
432+
return Err(format_one_arg(message, self.get_driver_name()).into());
433+
}
434+
Ok(())
435+
}
436+
427437
// ----------------------------------------------------------
428438
// Getters and setters for configuration parameters
429439
// ----------------------------------------------------------
@@ -493,7 +503,7 @@ pub trait SeleniumManager {
493503
.unwrap()
494504
.to_string()
495505
.replace("\\\\?\\", "")
496-
.replace("\\", "\\\\");
506+
.replace('\\', "\\\\");
497507
}
498508
browser_path
499509
}
@@ -510,7 +520,7 @@ pub trait SeleniumManager {
510520
}
511521

512522
fn set_proxy(&mut self, proxy: String) -> Result<(), Box<dyn Error>> {
513-
if !proxy.is_empty() {
523+
if !proxy.is_empty() && !self.is_offline() {
514524
self.get_logger().debug(format!("Using proxy: {}", &proxy));
515525
let mut config = self.get_config_mut();
516526
config.proxy = proxy;
@@ -557,6 +567,16 @@ pub trait SeleniumManager {
557567
fn set_browser_ttl(&mut self, browser_ttl: u64) {
558568
self.get_config_mut().browser_ttl = browser_ttl;
559569
}
570+
571+
fn is_offline(&self) -> bool {
572+
self.get_config().offline
573+
}
574+
575+
fn set_offline(&mut self, offline: bool) {
576+
if offline {
577+
self.get_config_mut().offline = true;
578+
}
579+
}
560580
}
561581

562582
// ----------------------------------------------------------

rust/src/main.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use std::process::exit;
2020
use clap::Parser;
2121

2222
use exitcode::DATAERR;
23+
use exitcode::UNAVAILABLE;
2324

2425
use exitcode::OK;
2526
use selenium_manager::config::BooleanKey;
@@ -103,6 +104,10 @@ struct Cli {
103104
/// Display TRACE messages
104105
#[clap(long)]
105106
trace: bool,
107+
108+
/// Offline mode (i.e., disabling network requests and downloads)
109+
#[clap(long)]
110+
offline: bool,
106111
}
107112

108113
fn main() {
@@ -149,20 +154,31 @@ fn main() {
149154
selenium_manager.set_browser_path(cli.browser_path.unwrap_or_default());
150155
selenium_manager.set_driver_ttl(cli.driver_ttl);
151156
selenium_manager.set_browser_ttl(cli.browser_ttl);
157+
selenium_manager.set_offline(cli.offline);
152158

153159
selenium_manager
154160
.set_timeout(cli.timeout)
155161
.and_then(|_| selenium_manager.set_proxy(cli.proxy.unwrap_or_default()))
156162
.and_then(|_| selenium_manager.resolve_driver())
157163
.map(|path| {
158164
let log = selenium_manager.get_logger();
159-
log.info(path.display());
160-
flush_and_exit(OK, log);
165+
if path.exists() {
166+
log.info(path.display());
167+
flush_and_exit(OK, log);
168+
} else {
169+
log.error("Driver unavailable in the cache".to_string());
170+
flush_and_exit(UNAVAILABLE, log);
171+
}
161172
})
162173
.unwrap_or_else(|err| {
163174
let log = selenium_manager.get_logger();
164-
log.error(err.to_string());
165-
flush_and_exit(DATAERR, log);
175+
if selenium_manager.is_offline() {
176+
log.warn(err.to_string());
177+
flush_and_exit(OK, log);
178+
} else {
179+
log.error(err.to_string());
180+
flush_and_exit(DATAERR, log);
181+
}
166182
});
167183
}
168184

rust/tests/offline_tests.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
use assert_cmd::Command;
19+
use std::str;
20+
21+
#[test]
22+
fn offline_test() {
23+
let mut cmd = Command::new(env!("CARGO_BIN_EXE_selenium-manager"));
24+
cmd.args([
25+
"--clear-cache",
26+
"--debug",
27+
"--browser",
28+
"chrome",
29+
"--offline",
30+
])
31+
.assert()
32+
.success()
33+
.code(0);
34+
35+
let stdout = &cmd.unwrap().stdout;
36+
let output = str::from_utf8(stdout).unwrap();
37+
println!("{output}");
38+
assert!(output.contains("WARN"));
39+
}

0 commit comments

Comments
 (0)