Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mozilla/geckodriver.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/capabilities.rs')
-rw-r--r--src/capabilities.rs288
1 files changed, 186 insertions, 102 deletions
diff --git a/src/capabilities.rs b/src/capabilities.rs
index a409cfe..278530e 100644
--- a/src/capabilities.rs
+++ b/src/capabilities.rs
@@ -4,16 +4,18 @@
use crate::command::LogOptions;
use crate::logging::Level;
-use base64;
+use crate::marionette::MarionetteSettings;
use mozdevice::AndroidStorageInput;
use mozprofile::preferences::Pref;
use mozprofile::profile::Profile;
+use mozrunner::firefox_args::{get_arg_value, parse_args, Arg};
use mozrunner::runner::platform::firefox_default_path;
use mozversion::{self, firefox_binary_version, firefox_version, Version};
use regex::bytes::Regex;
use serde_json::{Map, Value};
use std::collections::BTreeMap;
use std::default::Default;
+use std::ffi::OsString;
use std::fmt::{self, Display};
use std::fs;
use std::io;
@@ -23,7 +25,6 @@ use std::path::{Path, PathBuf};
use std::str::{self, FromStr};
use webdriver::capabilities::{BrowserCapabilities, Capabilities};
use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult};
-use zip;
#[derive(Clone, Debug)]
enum VersionError {
@@ -154,6 +155,10 @@ impl<'a> BrowserCapabilities for FirefoxCapabilities<'a> {
Ok(true)
}
+ fn accept_proxy(&mut self, _: &Capabilities, _: &Capabilities) -> WebDriverResult<bool> {
+ Ok(true)
+ }
+
fn set_window_rect(&mut self, _: &Capabilities) -> WebDriverResult<bool> {
Ok(true)
}
@@ -164,7 +169,7 @@ impl<'a> BrowserCapabilities for FirefoxCapabilities<'a> {
comparison: &str,
) -> WebDriverResult<bool> {
Version::from_str(version)
- .map_err(|err| VersionError::from(err))?
+ .map_err(VersionError::from)?
.matches(comparison)
.map_err(|err| VersionError::from(err).into())
}
@@ -173,8 +178,10 @@ impl<'a> BrowserCapabilities for FirefoxCapabilities<'a> {
Ok(true)
}
- fn accept_proxy(&mut self, _: &Capabilities, _: &Capabilities) -> WebDriverResult<bool> {
- Ok(true)
+ fn web_socket_url(&mut self, caps: &Capabilities) -> WebDriverResult<bool> {
+ self.browser_version(caps)?
+ .map(|v| self.compare_browser_version(&v, ">=90"))
+ .unwrap_or(Ok(false))
}
fn validate_custom(&mut self, name: &str, value: &Value) -> WebDriverResult<()> {
@@ -377,6 +384,7 @@ pub struct FirefoxOptions {
pub log: LogOptions,
pub prefs: Vec<(String, Pref)>,
pub android: Option<AndroidOptions>,
+ pub use_websocket: bool,
}
impl FirefoxOptions {
@@ -384,9 +392,9 @@ impl FirefoxOptions {
Default::default()
}
- pub fn from_capabilities(
+ pub(crate) fn from_capabilities(
binary_path: Option<PathBuf>,
- android_storage: AndroidStorageInput,
+ settings: &MarionetteSettings,
matched: &mut Capabilities,
) -> WebDriverResult<FirefoxOptions> {
let mut rv = FirefoxOptions::new();
@@ -401,7 +409,7 @@ impl FirefoxOptions {
)
})?;
- rv.android = FirefoxOptions::load_android(android_storage, &options)?;
+ rv.android = FirefoxOptions::load_android(settings.android_storage, &options)?;
rv.args = FirefoxOptions::load_args(&options)?;
rv.env = FirefoxOptions::load_env(&options)?;
rv.log = FirefoxOptions::load_log(&options)?;
@@ -409,32 +417,62 @@ impl FirefoxOptions {
rv.profile = FirefoxOptions::load_profile(&options)?;
}
- if let Some(json) = matched.remove("moz:debuggerAddress") {
- let use_web_socket = json.as_bool().ok_or_else(|| {
- WebDriverError::new(
- ErrorStatus::InvalidArgument,
- "moz:debuggerAddress is not a boolean",
- )
- })?;
+ if let Some(args) = rv.args.as_ref() {
+ let os_args = parse_args(args.iter().map(OsString::from).collect::<Vec<_>>().iter());
+ if let Some(path) = get_arg_value(os_args.iter(), Arg::Profile) {
+ if rv.profile.is_some() {
+ return Err(WebDriverError::new(
+ ErrorStatus::InvalidArgument,
+ "Can't provide both a --profile argument and a profile",
+ ));
+ }
+ let path_buf = PathBuf::from(path);
+ rv.profile = Some(Profile::new_from_path(&path_buf)?);
+ }
- if use_web_socket {
- let mut remote_args = Vec::new();
- remote_args.push("--remote-debugging-port".to_owned());
- remote_args.push("0".to_owned());
+ if get_arg_value(os_args.iter(), Arg::NamedProfile).is_some() && rv.profile.is_some() {
+ return Err(WebDriverError::new(
+ ErrorStatus::InvalidArgument,
+ "Can't provide both a -P argument and a profile",
+ ));
+ }
+ }
- if let Some(ref mut args) = rv.args {
- args.append(&mut remote_args);
- } else {
- rv.args = Some(remote_args);
- }
+ let has_web_socket_url = matched
+ .get("webSocketUrl")
+ .and_then(|x| x.as_bool())
+ .unwrap_or(false);
+
+ let has_debugger_address = matched
+ .remove("moz:debuggerAddress")
+ .and_then(|x| x.as_bool())
+ .unwrap_or(false);
+
+ // Set a command line provided port for the Remote Agent for now.
+ // It needs to be the same on the host and the Android device.
+ if has_web_socket_url || has_debugger_address {
+ rv.use_websocket = true;
+
+ // Bug 1722863: Setting of command line arguments would be
+ // better suited in the individual Browser implementations.
+ let mut remote_args = Vec::new();
+ remote_args.push("--remote-debugging-port".to_owned());
+ remote_args.push(settings.websocket_port.to_string());
+
+ if let Some(ref mut args) = rv.args {
+ args.append(&mut remote_args);
+ } else {
+ rv.args = Some(remote_args);
+ }
+ }
- // Force Fission disabled until Remote Agent is compatible,
- // and preference hasn't been already set
- let has_fission_pref = rv.prefs.iter().find(|&x| x.0 == "fission.autostart");
- if has_fission_pref.is_none() {
- rv.prefs
- .push(("fission.autostart".to_owned(), Pref::new(false)));
- }
+ // Force Fission disabled until the CDP implementation is compatible,
+ // and preference hasn't been already set
+ if has_debugger_address {
+ let has_fission_pref = rv.prefs.iter().find(|&x| x.0 == "fission.autostart");
+ if has_fission_pref.is_none() {
+ rv.prefs
+ .push(("fission.autostart".to_owned(), Pref::new(false)));
}
}
@@ -597,7 +635,7 @@ impl FirefoxOptions {
})?
.to_owned();
- if activity.contains("/") {
+ if activity.contains('/') {
return Err(WebDriverError::new(
ErrorStatus::InvalidArgument,
"androidActivity should not contain '/",
@@ -671,7 +709,7 @@ impl FirefoxOptions {
"-d".to_string(),
"about:blank".to_string(),
])
- },
+ }
};
Ok(Some(android))
@@ -751,10 +789,7 @@ mod tests {
use self::mozprofile::preferences::Pref;
use super::*;
- use crate::marionette::MarionetteHandler;
- use mozdevice::AndroidStorageInput;
- use serde_json::json;
- use std::default::Default;
+ use serde_json::{json, Map, Value};
use std::fs::File;
use std::io::Read;
@@ -767,16 +802,19 @@ mod tests {
Value::String(base64::encode(&profile_data))
}
- fn make_options(firefox_opts: Capabilities) -> WebDriverResult<FirefoxOptions> {
+ fn make_options(
+ firefox_opts: Capabilities,
+ marionette_settings: Option<MarionetteSettings>,
+ ) -> WebDriverResult<FirefoxOptions> {
let mut caps = Capabilities::new();
caps.insert("moz:firefoxOptions".into(), Value::Object(firefox_opts));
- FirefoxOptions::from_capabilities(None, AndroidStorageInput::Auto, &mut caps)
+ FirefoxOptions::from_capabilities(None, &marionette_settings.unwrap_or_default(), &mut caps)
}
#[test]
fn fx_options_default() {
- let opts = FirefoxOptions::new();
+ let opts: FirefoxOptions = Default::default();
assert_eq!(opts.android, None);
assert_eq!(opts.args, None);
assert_eq!(opts.binary, None);
@@ -787,11 +825,12 @@ mod tests {
}
#[test]
- fn fx_options_from_capabilities_no_binary_and_caps() {
+ fn fx_options_from_capabilities_no_binary_and_empty_caps() {
let mut caps = Capabilities::new();
- let opts =
- FirefoxOptions::from_capabilities(None, AndroidStorageInput::Auto, &mut caps).unwrap();
+ let marionette_settings = Default::default();
+ let opts = FirefoxOptions::from_capabilities(None, &marionette_settings, &mut caps)
+ .expect("valid firefox options");
assert_eq!(opts.android, None);
assert_eq!(opts.args, None);
assert_eq!(opts.binary, None);
@@ -808,13 +847,14 @@ mod tests {
);
let binary = PathBuf::from("foo");
+ let marionette_settings = Default::default();
let opts = FirefoxOptions::from_capabilities(
Some(binary.clone()),
- AndroidStorageInput::Auto,
+ &marionette_settings,
&mut caps,
)
- .unwrap();
+ .expect("valid firefox options");
assert_eq!(opts.android, None);
assert_eq!(opts.args, None);
assert_eq!(opts.binary, Some(binary));
@@ -823,10 +863,11 @@ mod tests {
}
#[test]
- fn fx_options_from_capabilities_with_debugger_address_not_set() {
+ fn fx_options_from_capabilities_with_websocket_url_not_set() {
let mut caps = Capabilities::new();
- let opts = FirefoxOptions::from_capabilities(None, AndroidStorageInput::Auto, &mut caps)
+ let marionette_settings = Default::default();
+ let opts = FirefoxOptions::from_capabilities(None, &marionette_settings, &mut caps)
.expect("Valid Firefox options");
assert!(
@@ -836,16 +877,63 @@ mod tests {
}
#[test]
- fn fx_options_from_capabilities_with_debugger_address_false() {
+ fn fx_options_from_capabilities_with_websocket_url_false() {
let mut caps = Capabilities::new();
- caps.insert("moz:debuggerAddress".into(), json!(false));
+ caps.insert("webSocketUrl".into(), json!(false));
- let opts = FirefoxOptions::from_capabilities(None, AndroidStorageInput::Auto, &mut caps)
+ let marionette_settings = Default::default();
+ let opts = FirefoxOptions::from_capabilities(None, &marionette_settings, &mut caps)
.expect("Valid Firefox options");
assert!(
opts.args.is_none(),
- "CLI arguments for remote protocol unexpectedly found"
+ "CLI arguments for Firefox unexpectedly found"
+ );
+ }
+
+ #[test]
+ fn fx_options_from_capabilities_with_websocket_url_true() {
+ let mut caps = Capabilities::new();
+ caps.insert("webSocketUrl".into(), json!(true));
+
+ let settings = MarionetteSettings {
+ websocket_port: 1234,
+ ..Default::default()
+ };
+ let opts = FirefoxOptions::from_capabilities(None, &settings, &mut caps)
+ .expect("Valid Firefox options");
+
+ if let Some(args) = opts.args {
+ let mut iter = args.iter();
+ assert!(iter
+ .find(|&arg| arg == &"--remote-debugging-port".to_owned())
+ .is_some());
+ assert_eq!(iter.next(), Some(&"1234".to_owned()));
+ } else {
+ assert!(false, "CLI arguments for Firefox not found");
+ }
+ }
+
+ #[test]
+ fn fx_options_from_capabilities_with_debugger_address_not_set() {
+ let caps = Capabilities::new();
+
+ let opts = make_options(caps, None).expect("valid firefox options");
+ assert!(
+ opts.args.is_none(),
+ "CLI arguments for Firefox unexpectedly found"
+ );
+ }
+
+ #[test]
+ fn fx_options_from_capabilities_with_debugger_address_false() {
+ let mut caps = Capabilities::new();
+ caps.insert("moz:debuggerAddress".into(), json!(false));
+
+ let opts = make_options(caps, None).expect("valid firefox options");
+ assert!(
+ opts.args.is_none(),
+ "CLI arguments for Firefox unexpectedly found"
);
}
@@ -854,7 +942,11 @@ mod tests {
let mut caps = Capabilities::new();
caps.insert("moz:debuggerAddress".into(), json!(true));
- let opts = FirefoxOptions::from_capabilities(None, AndroidStorageInput::Auto, &mut caps)
+ let settings = MarionetteSettings {
+ websocket_port: 1234,
+ ..Default::default()
+ };
+ let opts = FirefoxOptions::from_capabilities(None, &settings, &mut caps)
.expect("Valid Firefox options");
if let Some(args) = opts.args {
@@ -862,9 +954,9 @@ mod tests {
assert!(iter
.find(|&arg| arg == &"--remote-debugging-port".to_owned())
.is_some());
- assert_eq!(iter.next(), Some(&"0".to_owned()));
+ assert_eq!(iter.next(), Some(&"1234".to_owned()));
} else {
- assert!(false, "CLI arguments for remote protocol not found");
+ assert!(false, "CLI arguments for Firefox not found");
}
assert!(opts
@@ -878,7 +970,8 @@ mod tests {
let mut caps = Capabilities::new();
caps.insert("moz:firefoxOptions".into(), json!(42));
- FirefoxOptions::from_capabilities(None, AndroidStorageInput::Auto, &mut caps)
+ let marionette_settings = Default::default();
+ FirefoxOptions::from_capabilities(None, &marionette_settings, &mut caps)
.expect_err("Firefox options need to be of type object");
}
@@ -887,7 +980,7 @@ mod tests {
let mut firefox_opts = Capabilities::new();
firefox_opts.insert("androidAvtivity".into(), json!("foo"));
- let opts = make_options(firefox_opts).expect("valid firefox options");
+ let opts = make_options(firefox_opts, None).expect("valid firefox options");
assert_eq!(opts.android, None);
}
@@ -897,7 +990,7 @@ mod tests {
let mut firefox_opts = Capabilities::new();
firefox_opts.insert("androidPackage".into(), json!(value));
- let opts = make_options(firefox_opts).expect("valid firefox options");
+ let opts = make_options(firefox_opts, None).expect("valid firefox options");
assert_eq!(opts.android.unwrap().package, value.to_string());
}
}
@@ -907,7 +1000,7 @@ mod tests {
let mut firefox_opts = Capabilities::new();
firefox_opts.insert("androidPackage".into(), json!(42));
- make_options(firefox_opts).expect_err("invalid firefox options");
+ make_options(firefox_opts, None).expect_err("invalid firefox options");
}
#[test]
@@ -915,7 +1008,7 @@ mod tests {
for value in ["../foo", "\\foo\n", "foo", "_foo", "0foo"].iter() {
let mut firefox_opts = Capabilities::new();
firefox_opts.insert("androidPackage".into(), json!(value));
- make_options(firefox_opts).expect_err("invalid firefox options");
+ make_options(firefox_opts, None).expect_err("invalid firefox options");
}
}
@@ -937,7 +1030,7 @@ mod tests {
let mut firefox_opts = Capabilities::new();
firefox_opts.insert("androidPackage".into(), json!(package));
- let opts = make_options(firefox_opts).expect("valid firefox options");
+ let opts = make_options(firefox_opts, None).expect("valid firefox options");
assert!(opts
.android
.unwrap()
@@ -955,7 +1048,7 @@ mod tests {
let mut firefox_opts = Capabilities::new();
firefox_opts.insert("androidPackage".into(), json!(package));
- let opts = make_options(firefox_opts).expect("valid firefox options");
+ let opts = make_options(firefox_opts, None).expect("valid firefox options");
assert_eq!(opts.android.unwrap().activity, None);
}
@@ -965,7 +1058,7 @@ mod tests {
json!("org.mozilla.geckoview_example"),
);
- let opts = make_options(firefox_opts).expect("valid firefox options");
+ let opts = make_options(firefox_opts, None).expect("valid firefox options");
assert_eq!(opts.android.unwrap().activity, None);
}
@@ -975,7 +1068,7 @@ mod tests {
firefox_opts.insert("androidPackage".into(), json!("foo.bar"));
firefox_opts.insert("androidActivity".into(), json!("foo"));
- let opts = make_options(firefox_opts).expect("valid firefox options");
+ let opts = make_options(firefox_opts, None).expect("valid firefox options");
assert_eq!(opts.android.unwrap().activity, Some("foo".to_string()));
}
@@ -985,7 +1078,7 @@ mod tests {
firefox_opts.insert("androidPackage".into(), json!("foo.bar"));
firefox_opts.insert("androidActivity".into(), json!(42));
- make_options(firefox_opts).expect_err("invalid firefox options");
+ make_options(firefox_opts, None).expect_err("invalid firefox options");
}
#[test]
@@ -994,7 +1087,7 @@ mod tests {
firefox_opts.insert("androidPackage".into(), json!("foo.bar"));
firefox_opts.insert("androidActivity".into(), json!("foo.bar/cheese"));
- make_options(firefox_opts).expect_err("invalid firefox options");
+ make_options(firefox_opts, None).expect_err("invalid firefox options");
}
#[test]
@@ -1003,7 +1096,7 @@ mod tests {
firefox_opts.insert("androidPackage".into(), json!("foo.bar"));
firefox_opts.insert("androidDeviceSerial".into(), json!("cheese"));
- let opts = make_options(firefox_opts).expect("valid firefox options");
+ let opts = make_options(firefox_opts, None).expect("valid firefox options");
assert_eq!(
opts.android.unwrap().device_serial,
Some("cheese".to_string())
@@ -1016,7 +1109,7 @@ mod tests {
firefox_opts.insert("androidPackage".into(), json!("foo.bar"));
firefox_opts.insert("androidDeviceSerial".into(), json!(42));
- make_options(firefox_opts).expect_err("invalid firefox options");
+ make_options(firefox_opts, None).expect_err("invalid firefox options");
}
#[test]
@@ -1035,7 +1128,7 @@ mod tests {
let mut firefox_opts = Capabilities::new();
firefox_opts.insert("androidPackage".into(), json!(package));
- let opts = make_options(firefox_opts).expect("valid firefox options");
+ let opts = make_options(firefox_opts, None).expect("valid firefox options");
assert_eq!(
opts.android.unwrap().intent_arguments,
Some(vec![
@@ -1054,7 +1147,7 @@ mod tests {
firefox_opts.insert("androidPackage".into(), json!("foo.bar"));
firefox_opts.insert("androidIntentArguments".into(), json!(["lorem", "ipsum"]));
- let opts = make_options(firefox_opts).expect("valid firefox options");
+ let opts = make_options(firefox_opts, None).expect("valid firefox options");
assert_eq!(
opts.android.unwrap().intent_arguments,
Some(vec!["lorem".to_string(), "ipsum".to_string()])
@@ -1067,7 +1160,7 @@ mod tests {
firefox_opts.insert("androidPackage".into(), json!("foo.bar"));
firefox_opts.insert("androidIntentArguments".into(), json!(42));
- make_options(firefox_opts).expect_err("invalid firefox options");
+ make_options(firefox_opts, None).expect_err("invalid firefox options");
}
#[test]
@@ -1076,7 +1169,7 @@ mod tests {
firefox_opts.insert("androidPackage".into(), json!("foo.bar"));
firefox_opts.insert("androidIntentArguments".into(), json!(["lorem", 42]));
- make_options(firefox_opts).expect_err("invalid firefox options");
+ make_options(firefox_opts, None).expect_err("invalid firefox options");
}
#[test]
@@ -1088,7 +1181,7 @@ mod tests {
let mut firefox_opts = Capabilities::new();
firefox_opts.insert("env".into(), env.into());
- let mut opts = make_options(firefox_opts).expect("valid firefox options");
+ let mut opts = make_options(firefox_opts, None).expect("valid firefox options");
for sorted in opts.env.iter_mut() {
sorted.sort()
}
@@ -1108,7 +1201,7 @@ mod tests {
let mut firefox_opts = Capabilities::new();
firefox_opts.insert("env".into(), env.into());
- make_options(firefox_opts).expect_err("invalid firefox options");
+ make_options(firefox_opts, None).expect_err("invalid firefox options");
}
#[test]
@@ -1119,7 +1212,7 @@ mod tests {
let mut firefox_opts = Capabilities::new();
firefox_opts.insert("env".into(), env.into());
- make_options(firefox_opts).expect_err("invalid firefox options");
+ make_options(firefox_opts, None).expect_err("invalid firefox options");
}
#[test]
@@ -1128,7 +1221,7 @@ mod tests {
let mut firefox_opts = Capabilities::new();
firefox_opts.insert("profile".into(), encoded_profile);
- let opts = make_options(firefox_opts).expect("valid firefox options");
+ let opts = make_options(firefox_opts, None).expect("valid firefox options");
let mut profile = opts.profile.expect("valid firefox profile");
let prefs = profile.user_prefs().expect("valid preferences");
@@ -1141,37 +1234,28 @@ mod tests {
}
#[test]
- fn test_prefs() {
- let encoded_profile = example_profile();
- let mut prefs: Map<String, Value> = Map::new();
- prefs.insert(
- "browser.display.background_color".into(),
- Value::String("#00ff00".into()),
- );
-
+ fn fx_options_args_profile() {
let mut firefox_opts = Capabilities::new();
- firefox_opts.insert("profile".into(), encoded_profile);
- firefox_opts.insert("prefs".into(), Value::Object(prefs));
+ firefox_opts.insert("args".into(), json!(["--profile", "foo"]));
- let opts = make_options(firefox_opts).expect("valid profile and prefs");
- let mut profile = opts.profile.expect("valid firefox profile");
+ make_options(firefox_opts, None).expect("Valid args");
+ }
- let handler = MarionetteHandler::new(Default::default());
- handler
- .set_prefs(2828, &mut profile, true, opts.prefs)
- .expect("set preferences");
+ #[test]
+ fn fx_options_args_profile_and_profile() {
+ let mut firefox_opts = Capabilities::new();
+ firefox_opts.insert("args".into(), json!(["--profile", "foo"]));
+ firefox_opts.insert("profile".into(), json!("foo"));
- let prefs_set = profile.user_prefs().expect("valid user preferences");
- println!("{:#?}", prefs_set.prefs);
+ make_options(firefox_opts, None).expect_err("Invalid args");
+ }
- assert_eq!(
- prefs_set.get("startup.homepage_welcome_url"),
- Some(&Pref::new("data:text/html,PASS"))
- );
- assert_eq!(
- prefs_set.get("browser.display.background_color"),
- Some(&Pref::new("#00ff00"))
- );
- assert_eq!(prefs_set.get("marionette.port"), Some(&Pref::new(2828)));
+ #[test]
+ fn fx_options_args_p_and_profile() {
+ let mut firefox_opts = Capabilities::new();
+ firefox_opts.insert("args".into(), json!(["-P"]));
+ firefox_opts.insert("profile".into(), json!("foo"));
+
+ make_options(firefox_opts, None).expect_err("Invalid args");
}
}