Commit 98a5cfa0 authored by Sylvestre Ledru's avatar Sylvestre Ledru
Browse files

Bug 1617369 - Reformat testing/ using rustfmt r=whimboo,webdriver-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D63940

--HG--
extra : moz-landing-system : lando
parent ab439621
use crate::capabilities::{AndroidOptions};
use crate::capabilities::AndroidOptions;
use mozdevice::{Device, Host};
use mozprofile::profile::Profile;
use serde::Serialize;
......@@ -12,8 +12,7 @@ use std::time;
// For now, we always use target port 2829, leading to issues like bug 1533704.
const TARGET_PORT: u16 = 2829;
const CONFIG_FILE_HEADING: &str =
r#"## GeckoView configuration YAML
const CONFIG_FILE_HEADING: &str = r#"## GeckoView configuration YAML
##
## Auto-generated by geckodriver.
## See https://mozilla.github.io/geckoview/consumer/docs/automation.
......@@ -35,14 +34,12 @@ impl fmt::Display for AndroidError {
match *self {
AndroidError::ActivityNotFound(ref package) => {
write!(f, "Activity not found for package '{}'", package)
},
}
AndroidError::Device(ref message) => message.fmt(f),
AndroidError::IO(ref message) => message.fmt(f),
AndroidError::NotConnected =>
write!(f, "Not connected to any Android device"),
AndroidError::NotConnected => write!(f, "Not connected to any Android device"),
AndroidError::Serde(ref message) => message.fmt(f),
}
}
}
......@@ -81,7 +78,11 @@ impl AndroidProcess {
package: String,
activity: String,
) -> mozdevice::Result<AndroidProcess> {
Ok(AndroidProcess { device, package, activity })
Ok(AndroidProcess {
device,
package,
activity,
})
}
}
......@@ -107,10 +108,14 @@ impl Drop for AndroidHandler {
}
match process.device.kill_forward_port(self.host_port) {
Ok(_) => debug!("Android port forward ({} -> {}) stopped",
&self.host_port, &self.target_port),
Err(e) => error!("Android port forward ({} -> {}) failed to stop: {}",
&self.host_port, &self.target_port, e),
Ok(_) => debug!(
"Android port forward ({} -> {}) stopped",
&self.host_port, &self.target_port
),
Err(e) => error!(
"Android port forward ({} -> {}) failed to stop: {}",
&self.host_port, &self.target_port, e
),
}
}
}
......@@ -123,7 +128,9 @@ impl AndroidHandler {
// This naming scheme follows GeckoView's configuration file naming scheme,
// see bug 1533385.
let profile = PathBuf::from(format!(
"/mnt/sdcard/{}-geckodriver-profile", &options.package));
"/mnt/sdcard/{}-geckodriver-profile",
&options.package
));
AndroidHandler {
options: options.clone(),
......@@ -148,7 +155,10 @@ impl AndroidHandler {
// Set up port forward. Port forwarding will be torn down, if possible,
device.forward_port(self.host_port, self.target_port)?;
debug!("Android port forward ({} -> {}) started", &self.host_port, &self.target_port);
debug!(
"Android port forward ({} -> {}) started",
&self.host_port, &self.target_port
);
// If activity hasn't been specified default to the main activity of the package
let activity = match self.options.activity {
......@@ -156,11 +166,9 @@ impl AndroidHandler {
None => {
let response = device.execute_host_shell_command(&format!(
"cmd package resolve-activity --brief {} | tail -n 1",
&self.options.package))?;
let parts = response
.trim_end()
.split('/')
.collect::<Vec<&str>>();
&self.options.package
))?;
let parts = response.trim_end().split('/').collect::<Vec<&str>>();
if parts.len() == 1 {
return Err(AndroidError::ActivityNotFound(self.options.package.clone()));
......@@ -183,7 +191,7 @@ impl AndroidHandler {
where
I: IntoIterator<Item = (K, V)>,
K: ToString,
V: ToString
V: ToString,
{
// To configure GeckoView, we use the automation techniques documented at
// https://mozilla.github.io/geckoview/consumer/docs/automation.
......@@ -223,7 +231,7 @@ impl AndroidHandler {
Value::String("1".to_owned()),
);
let mut contents: Vec<String> = vec!(CONFIG_FILE_HEADING.to_owned());
let mut contents: Vec<String> = vec![CONFIG_FILE_HEADING.to_owned()];
contents.push(serde_yaml::to_string(&config)?);
Ok(contents.concat())
......@@ -233,7 +241,7 @@ impl AndroidHandler {
where
I: IntoIterator<Item = (K, V)>,
K: ToString,
V: ToString
V: ToString,
{
match self.process {
Some(ref process) => {
......@@ -242,38 +250,52 @@ impl AndroidHandler {
// These permissions, at least, are required to read profiles in /mnt/sdcard.
for perm in &["READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE"] {
process.device.execute_host_shell_command(&format!(
"pm grant {} android.permission.{}", &process.package, perm))?;
"pm grant {} android.permission.{}",
&process.package, perm
))?;
}
debug!("Deleting {}", self.profile.display());
process.device.execute_host_shell_command(&format!(
"rm -rf {}", self.profile.display()))?;
debug!("Pushing {} to {}", profile.path.display(), self.profile.display());
process.device.push_dir(&profile.path, &self.profile, 0o777)?;
process
.device
.execute_host_shell_command(&format!("rm -rf {}", self.profile.display()))?;
debug!(
"Pushing {} to {}",
profile.path.display(),
self.profile.display()
);
process
.device
.push_dir(&profile.path, &self.profile, 0o777)?;
let target_path = PathBuf::from(format!(
"/data/local/tmp/{}-geckoview-config.yaml",
process.package));
process.package
));
let contents = self.generate_config_file(env)?;
debug!("Content of generated GeckoView config file:\n{}", contents);
let reader = &mut io::BufReader::new(contents.as_bytes());
debug!("Pushing GeckoView configuration file to {}", target_path.display());
debug!(
"Pushing GeckoView configuration file to {}",
target_path.display()
);
process.device.push(reader, &target_path, 0o777)?;
// Bug 1584966: File permissions are not correctly set by push()
process.device.execute_host_shell_command(&format!(
"chmod a+rw {}",
target_path.display()))?;
process
.device
.execute_host_shell_command(&format!("chmod a+rw {}", target_path.display()))?;
// Tell GeckoView to read configuration even when `android:debuggable="false"`.
process.device.execute_host_shell_command(&format!(
"am set-debug-app --persistent {}",
process.package))?;
},
None => return Err(AndroidError::NotConnected)
process.package
))?;
}
None => return Err(AndroidError::NotConnected),
}
Ok(())
......@@ -285,23 +307,29 @@ impl AndroidHandler {
// TODO: Remove the usage of intent arguments once Fennec is no longer
// supported. Packages which are using GeckoView always read the arguments
// via the YAML configuration file.
let mut intent_arguments = self.options.intent_arguments.clone()
let mut intent_arguments = self
.options
.intent_arguments
.clone()
.unwrap_or_else(|| Vec::with_capacity(3));
intent_arguments.push("--es".to_owned());
intent_arguments.push("args".to_owned());
intent_arguments.push(format!(
"-marionette -profile {}", self.profile.display()).to_owned());
intent_arguments
.push(format!("-marionette -profile {}", self.profile.display()).to_owned());
debug!("Launching {}/{}", process.package, process.activity);
process.device
process
.device
.launch(&process.package, &process.activity, &intent_arguments)
.map_err(|e| {
let message = format!(
"Could not launch Android {}/{}: {}", process.package, process.activity, e);
"Could not launch Android {}/{}: {}",
process.package, process.activity, e
);
mozdevice::DeviceError::Adb(message)
})?;
},
None => return Err(AndroidError::NotConnected)
}
None => return Err(AndroidError::NotConnected),
}
Ok(())
......@@ -312,10 +340,10 @@ impl AndroidHandler {
Some(process) => {
debug!("Force stopping the Android package: {}", &process.package);
process.device.force_stop(&process.package)?;
},
None => return Err(AndroidError::NotConnected)
}
None => return Err(AndroidError::NotConnected),
}
Ok(())
}
}
}
......@@ -181,11 +181,11 @@ impl<'a> BrowserCapabilities for FirefoxCapabilities<'a> {
);
for (key, value) in data.iter() {
match &**key {
"androidActivity" |
"androidDeviceSerial" |
"androidPackage" |
"binary" |
"profile" => {
"androidActivity"
| "androidDeviceSerial"
| "androidPackage"
| "binary"
| "profile" => {
if !value.is_string() {
return Err(WebDriverError::new(
ErrorStatus::InvalidArgument,
......@@ -193,8 +193,7 @@ impl<'a> BrowserCapabilities for FirefoxCapabilities<'a> {
));
}
}
"androidIntentArguments" |
"args" => {
"androidIntentArguments" | "args" => {
if !try_opt!(
value.as_array(),
ErrorStatus::InvalidArgument,
......@@ -258,7 +257,7 @@ impl<'a> BrowserCapabilities for FirefoxCapabilities<'a> {
ErrorStatus::InvalidArgument,
"prefs value is not an object"
);
let is_pref_value_type = |x:&Value| {
let is_pref_value_type = |x: &Value| {
x.is_string() || x.is_i64() || x.is_u64() || x.is_boolean()
};
if !prefs_data.values().all(is_pref_value_type) {
......@@ -358,11 +357,13 @@ impl FirefoxOptions {
rv.binary = binary_path;
if let Some(json) = matched.remove("moz:firefoxOptions") {
let options = json.as_object().ok_or_else(|| WebDriverError::new(
ErrorStatus::InvalidArgument,
"'moz:firefoxOptions' \
let options = json.as_object().ok_or_else(|| {
WebDriverError::new(
ErrorStatus::InvalidArgument,
"'moz:firefoxOptions' \
capability is not an object",
))?;
)
})?;
rv.android = FirefoxOptions::load_android(&options)?;
rv.args = FirefoxOptions::load_args(&options)?;
......@@ -377,10 +378,9 @@ impl FirefoxOptions {
fn load_profile(options: &Capabilities) -> WebDriverResult<Option<Profile>> {
if let Some(profile_json) = options.get("profile") {
let profile_base64 = profile_json.as_str().ok_or_else(|| WebDriverError::new(
ErrorStatus::InvalidArgument,
"Profile is not a string",
))?;
let profile_base64 = profile_json.as_str().ok_or_else(|| {
WebDriverError::new(ErrorStatus::InvalidArgument, "Profile is not a string")
})?;
let profile_zip = &*base64::decode(profile_base64)?;
// Create an emtpy profile directory
......@@ -402,19 +402,23 @@ impl FirefoxOptions {
fn load_args(options: &Capabilities) -> WebDriverResult<Option<Vec<String>>> {
if let Some(args_json) = options.get("args") {
let args_array = args_json.as_array().ok_or_else(|| WebDriverError::new(
ErrorStatus::InvalidArgument,
"Arguments were not an \
let args_array = args_json.as_array().ok_or_else(|| {
WebDriverError::new(
ErrorStatus::InvalidArgument,
"Arguments were not an \
array",
))?;
)
})?;
let args = args_array
.iter()
.map(|x| x.as_str().map(|x| x.to_owned()))
.collect::<Option<Vec<String>>>()
.ok_or_else(|| WebDriverError::new(
ErrorStatus::InvalidArgument,
"Arguments entries were not all strings",
))?;
.ok_or_else(|| {
WebDriverError::new(
ErrorStatus::InvalidArgument,
"Arguments entries were not all strings",
)
})?;
Ok(Some(args))
} else {
Ok(None)
......@@ -423,17 +427,23 @@ impl FirefoxOptions {
pub fn load_env(options: &Capabilities) -> WebDriverResult<Option<Vec<(String, String)>>> {
if let Some(env_data) = options.get("env") {
let env = env_data.as_object().ok_or_else(|| WebDriverError::new(
ErrorStatus::InvalidArgument,
"Env was not an object",
))?;
let env = env_data.as_object().ok_or_else(|| {
WebDriverError::new(ErrorStatus::InvalidArgument, "Env was not an object")
})?;
let mut rv = Vec::with_capacity(env.len());
for (key, value) in env.iter() {
rv.push((key.clone(),
value.as_str().ok_or_else(|| WebDriverError::new(
ErrorStatus::InvalidArgument,
"Env value is not a string",
))?.to_string()));
rv.push((
key.clone(),
value
.as_str()
.ok_or_else(|| {
WebDriverError::new(
ErrorStatus::InvalidArgument,
"Env value is not a string",
)
})?
.to_string(),
));
}
Ok(Some(rv))
} else {
......@@ -443,21 +453,21 @@ impl FirefoxOptions {
fn load_log(options: &Capabilities) -> WebDriverResult<LogOptions> {
if let Some(json) = options.get("log") {
let log = json.as_object().ok_or_else(|| WebDriverError::new(
ErrorStatus::InvalidArgument,
"Log section is not an object",
))?;
let log = json.as_object().ok_or_else(|| {
WebDriverError::new(ErrorStatus::InvalidArgument, "Log section is not an object")
})?;
let level = match log.get("level") {
Some(json) => {
let s = json.as_str().ok_or_else(|| WebDriverError::new(
ErrorStatus::InvalidArgument,
"Log level is not a string",
))?;
Some(Level::from_str(s).ok().ok_or_else(|| WebDriverError::new(
ErrorStatus::InvalidArgument,
"Log level is unknown",
))?)
let s = json.as_str().ok_or_else(|| {
WebDriverError::new(
ErrorStatus::InvalidArgument,
"Log level is not a string",
)
})?;
Some(Level::from_str(s).ok().ok_or_else(|| {
WebDriverError::new(ErrorStatus::InvalidArgument, "Log level is unknown")
})?)
}
None => None,
};
......@@ -470,10 +480,9 @@ impl FirefoxOptions {
pub fn load_prefs(options: &Capabilities) -> WebDriverResult<Vec<(String, Pref)>> {
if let Some(prefs_data) = options.get("prefs") {
let prefs = prefs_data.as_object().ok_or_else(|| WebDriverError::new(
ErrorStatus::InvalidArgument,
"Prefs were not an object",
))?;
let prefs = prefs_data.as_object().ok_or_else(|| {
WebDriverError::new(ErrorStatus::InvalidArgument, "Prefs were not an object")
})?;
let mut rv = Vec::with_capacity(prefs.len());
for (key, value) in prefs.iter() {
rv.push((key.clone(), pref_from_json(value)?));
......@@ -486,51 +495,68 @@ impl FirefoxOptions {
pub fn load_android(options: &Capabilities) -> WebDriverResult<Option<AndroidOptions>> {
if let Some(package_json) = options.get("androidPackage") {
let package = package_json.as_str().ok_or_else(|| WebDriverError::new(
ErrorStatus::InvalidArgument,
"androidPackage was not a string"
))?.to_owned();
let package = package_json
.as_str()
.ok_or_else(|| {
WebDriverError::new(
ErrorStatus::InvalidArgument,
"androidPackage was not a string",
)
})?
.to_owned();
let mut android = AndroidOptions::new(package);
android.activity = match options.get("androidActivity") {
Some(json) => {
Some(json.as_str().ok_or_else(|| WebDriverError::new(
ErrorStatus::InvalidArgument,
"androidActivity was not a string"
))?.to_owned())
},
None => None
Some(json) => Some(
json.as_str()
.ok_or_else(|| {
WebDriverError::new(
ErrorStatus::InvalidArgument,
"androidActivity was not a string",
)
})?
.to_owned(),
),
None => None,
};
android.device_serial = match options.get("androidDeviceSerial") {
Some(json) => {
Some(json.as_str().ok_or_else(|| WebDriverError::new(
ErrorStatus::InvalidArgument,
"androidDeviceSerial was not a string"
))?.to_owned())
},
None => None
Some(json) => Some(
json.as_str()
.ok_or_else(|| {
WebDriverError::new(
ErrorStatus::InvalidArgument,
"androidDeviceSerial was not a string",
)
})?
.to_owned(),
),
None => None,
};
android.intent_arguments = match options.get("androidIntentArguments") {
Some(json) => {
let args_array = json.as_array().ok_or_else(|| WebDriverError::new(
ErrorStatus::InvalidArgument,
"androidIntentArguments were not an array"
))?;
let args_array = json.as_array().ok_or_else(|| {
WebDriverError::new(
ErrorStatus::InvalidArgument,
"androidIntentArguments were not an array",
)
})?;
let args = args_array
.iter()
.map(|x| x.as_str().map(|x| x.to_owned()))
.collect::<Option<Vec<String>>>()
.ok_or_else(|| WebDriverError::new(
ErrorStatus::InvalidArgument,
"androidIntentArguments entries were not all strings"
))?;
.ok_or_else(|| {
WebDriverError::new(
ErrorStatus::InvalidArgument,
"androidIntentArguments entries were not all strings",
)
})?;
Some(args)
}
None => None
None => None,
};
Ok(Some(android))
......@@ -660,7 +686,10 @@ mod tests {
#[test]
fn fx_options_from_capabilities_with_binary_and_caps() {
let mut caps = Capabilities::new();
caps.insert("moz:firefoxOptions".into(), Value::Object(Capabilities::new()));
caps.insert(
"moz:firefoxOptions".into(),
Value::Object(Capabilities::new()),
);
let binary = PathBuf::from("foo");
......@@ -791,24 +820,23 @@ mod tests {
#[test]
fn fx_options_env() {
let mut env: Map<String, Value> = Map::new();
env.insert(
"TEST_KEY_A".into(),
Value::String("test_value_a".into()),
);
env.insert(
"TEST_KEY_B".into(),
Value::String("test_value_b".into()),
);
env.insert("TEST_KEY_A".into(), Value::String("test_value_a".into()));
env.insert("TEST_KEY_B".into(), Value::String("test_value_b".into()));
let mut firefox_opts = Capabilities::new();
firefox_opts.insert("env".into(), env.into());
let mut opts = make_options(firefox_opts).expect("valid firefox options");
for sorted in opts.env.iter_mut() { sorted.sort() };
assert_eq!(opts.env, Some(vec![
("TEST_KEY_A".into(), "test_value_a".into()),
("TEST_KEY_B".into(), "test_value_b".into()),
]));
for sorted in opts.env.iter_mut() {
sorted.sort()
}
assert_eq!(
opts.env,
Some(vec![
("TEST_KEY_A".into(), "test_value_a".into()),
("TEST_KEY_B".into(), "test_value_b".into()),
])
);
}
#[test]
......@@ -824,10 +852,7 @@ mod tests {
#[test]
fn fx_options_env_invalid_value() {
let mut env: Map<String, Value> = Map::new();
env.insert(
"TEST_KEY".into(),
Value::Number(1.into()),
);
env.insert("TEST_KEY".into(), Value::Number(1.into()));
let mut firefox_opts = Capabilities::new();
firefox_opts.insert("env".into(), env.into());
......
......@@ -340,10 +340,7 @@ where
{
let val = f64::deserialize(deserializer)?;
if val < 0.1 || val > 2.0 {
return Err(de::Error::custom(format!(
"{} is outside range 0.1-2",
val
)));
return Err(de::Error::custom(format!("{} is outside range 0.1-2", val)));
};
Ok(val)
}
......
use crate::android::{AndroidHandler};
use crate::android::AndroidHandler;
use crate::command::{
AddonInstallParameters, AddonUninstallParameters, GeckoContextParameters,
GeckoExtensionCommand, GeckoExtensionRoute, PrintParameters,
XblLocatorParameters, CHROME_ELEMENT_KEY,
GeckoExtensionCommand, GeckoExtensionRoute, PrintParameters, XblLocatorParameters,
CHROME_ELEMENT_KEY,
};
use marionette_rs::common::{
Cookie as MarionetteCookie, Date as MarionetteDate, Frame as MarionetteFrame,
......@@ -121,10 +121,12 @@ impl MarionetteHandler {
let mut fx_capabilities = FirefoxCapabilities::new(self.settings.binary.as_ref());
let mut capabilities = new_session_parameters
.match_browser(&mut fx_capabilities)?
.ok_or_else(|| WebDriverError::new(
ErrorStatus::SessionNotCreated,
"Unable to find a matching set of capabilities",
))?;