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:
authorAndreas Tolfsen <ato@mozilla.com>2016-09-30 19:41:32 +0300
committerAndreas Tolfsen <ato@mozilla.com>2016-10-05 18:49:33 +0300
commitaa4221b8f925a36926789e3b12c331cc69521a3d (patch)
treea7a81e6bc08741d5371de425d2d3ff8c337df7fa /src/capabilities.rs
parent312be489f34f08b6f7735c18b0f5ca9c2dbc66e6 (diff)
move FirefoxOptions to new file src/capabilities.rs
This provides slightly better code organisation and reduces length of the src/marionette.rs file.
Diffstat (limited to 'src/capabilities.rs')
-rw-r--r--src/capabilities.rs292
1 files changed, 292 insertions, 0 deletions
diff --git a/src/capabilities.rs b/src/capabilities.rs
new file mode 100644
index 0000000..9fe1dc4
--- /dev/null
+++ b/src/capabilities.rs
@@ -0,0 +1,292 @@
+use std::collections::BTreeMap;
+use std::fs;
+use std::io;
+use std::io::BufWriter;
+use std::io::Cursor;
+use std::path::{Path, PathBuf};
+use std::str::FromStr;
+
+use marionette::LogOptions;
+use mozprofile::preferences::Pref;
+use mozprofile::profile::Profile;
+use rustc_serialize::base64::FromBase64;
+use rustc_serialize::json::Json;
+use webdriver::command::NewSessionParameters;
+use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult};
+use zip;
+
+use logging::LogLevel;
+
+#[derive(Default)]
+pub struct FirefoxOptions {
+ pub binary: Option<PathBuf>,
+ pub profile: Option<Profile>,
+ pub args: Option<Vec<String>>,
+ pub log: LogOptions,
+ pub prefs: Vec<(String, Pref)>
+}
+
+impl FirefoxOptions {
+ pub fn from_capabilities(capabilities: &mut NewSessionParameters) -> WebDriverResult<FirefoxOptions> {
+ if let Some(options) = capabilities.consume("moz:firefoxOptions") {
+ let firefox_options = try!(options
+ .as_object()
+ .ok_or(WebDriverError::new(
+ ErrorStatus::InvalidArgument,
+ "'moz:firefoxOptions' capability was not an object")));
+ let binary = try!(FirefoxOptions::load_binary(&firefox_options));
+ let profile = try!(FirefoxOptions::load_profile(&firefox_options));
+ let args = try!(FirefoxOptions::load_args(&firefox_options));
+ let log = try!(FirefoxOptions::load_log(&firefox_options));
+ let prefs = try!(FirefoxOptions::load_prefs(&firefox_options));
+
+ Ok(FirefoxOptions {
+ binary: binary,
+ profile: profile,
+ args: args,
+ log: log,
+ prefs: prefs,
+ })
+ } else {
+ Ok(Default::default())
+ }
+ }
+
+ fn load_binary(options: &BTreeMap<String, Json>) -> WebDriverResult<Option<PathBuf>> {
+ if let Some(path) = options.get("binary") {
+ Ok(Some(PathBuf::from(try!(path
+ .as_string()
+ .ok_or(WebDriverError::new(
+ ErrorStatus::InvalidArgument,
+ "'binary' capability was not a string"))))))
+ } else {
+ Ok(None)
+ }
+ }
+
+ fn load_profile(options: &BTreeMap<String, Json>) -> WebDriverResult<Option<Profile>> {
+ if let Some(profile_json) = options.get("profile") {
+ let profile_base64 = try!(profile_json
+ .as_string()
+ .ok_or(
+ WebDriverError::new(ErrorStatus::UnknownError,
+ "Profile was not a string")));
+ let profile_zip = &*try!(profile_base64.from_base64());
+
+ // Create an emtpy profile directory
+ let profile = try!(Profile::new(None));
+ try!(unzip_buffer(profile_zip,
+ profile.temp_dir
+ .as_ref()
+ .expect("Profile doesn't have a path")
+ .path()));
+
+ Ok(Some(profile))
+ } else {
+ Ok(None)
+ }
+ }
+
+ fn load_args(options: &BTreeMap<String, Json>) -> WebDriverResult<Option<Vec<String>>> {
+ if let Some(args_json) = options.get("args") {
+ let args_array = try!(args_json.as_array()
+ .ok_or(WebDriverError::new(ErrorStatus::UnknownError,
+ "Arguments were not an array")));
+ let args = try!(args_array
+ .iter()
+ .map(|x| x.as_string().map(|x| x.to_owned()))
+ .collect::<Option<Vec<String>>>()
+ .ok_or(WebDriverError::new(
+ ErrorStatus::UnknownError,
+ "Arguments entries were not all strings")));
+ Ok(Some(args))
+ } else {
+ Ok(None)
+ }
+ }
+
+ fn load_log(options: &BTreeMap<String, Json>) -> WebDriverResult<LogOptions> {
+ if let Some(json) = options.get("log") {
+ let log = try!(json.as_object()
+ .ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, "Log section is not an object")));
+
+ let level = match log.get("level") {
+ Some(json) => {
+ let s = try!(json.as_string()
+ .ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, "Log level is not a string")));
+ Some(try!(LogLevel::from_str(s).ok()
+ .ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, "Log level is unknown"))))
+ },
+ None => None,
+ };
+
+ Ok(LogOptions { level: level })
+
+ } else {
+ Ok(Default::default())
+ }
+ }
+
+ pub fn load_prefs(options: &BTreeMap<String, Json>) -> WebDriverResult<Vec<(String, Pref)>> {
+ if let Some(prefs_data) = options.get("prefs") {
+ let prefs = try!(prefs_data
+ .as_object()
+ .ok_or(WebDriverError::new(ErrorStatus::UnknownError,"Prefs were not an object")));
+ let mut rv = Vec::with_capacity(prefs.len());
+ for (key, value) in prefs.iter() {
+ rv.push((key.clone(), try!(pref_from_json(value))));
+ };
+ Ok(rv)
+ } else {
+ Ok(vec![])
+ }
+ }
+}
+
+fn pref_from_json(value: &Json) -> WebDriverResult<Pref> {
+ match value {
+ &Json::String(ref x) => Ok(Pref::new(x.clone())),
+ &Json::I64(x) => Ok(Pref::new(x)),
+ &Json::U64(x) => Ok(Pref::new(x as i64)),
+ &Json::Boolean(x) => Ok(Pref::new(x)),
+ _ => Err(WebDriverError::new(ErrorStatus::UnknownError,
+ "Could not convert pref value to string, boolean, or integer"))
+ }
+}
+
+fn unzip_buffer(buf: &[u8], dest_dir: &Path) -> WebDriverResult<()> {
+ let reader = Cursor::new(buf);
+ let mut zip = try!(zip::ZipArchive::new(reader).map_err(|_| {
+ WebDriverError::new(ErrorStatus::UnknownError, "Failed to unzip profile")
+ }));
+
+ for i in 0..zip.len() {
+ let mut file = try!(zip.by_index(i).map_err(|_| {
+ WebDriverError::new(ErrorStatus::UnknownError, "Processing profile zip file failed")
+ }));
+ let unzip_path = {
+ let name = file.name();
+ let is_dir = name.ends_with("/");
+ let rel_path = Path::new(name);
+ let dest_path = dest_dir.join(rel_path);
+
+ {
+ let create_dir = if is_dir {
+ Some(dest_path.as_path())
+ } else {
+ dest_path.parent()
+ };
+ if let Some(dir) = create_dir {
+ if !dir.exists() {
+ debug!("Creating profile directory tree {}", dir.to_string_lossy());
+ try!(fs::create_dir_all(dir));
+ }
+ }
+ }
+
+ if is_dir {
+ None
+ } else {
+ Some(dest_path)
+ }
+ };
+
+ if let Some(unzip_path) = unzip_path {
+ debug!("Extracting profile to {}", unzip_path.to_string_lossy());
+ let dest = try!(fs::File::create(unzip_path));
+ let mut writer = BufWriter::new(dest);
+ try!(io::copy(&mut file, &mut writer));
+ }
+ }
+
+ Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+ extern crate mozprofile;
+ extern crate rustc_serialize;
+
+ use std::collections::BTreeMap;
+ use std::default::Default;
+ use std::fs::File;
+ use std::io::Read;
+
+ use self::mozprofile::preferences::Pref;
+ use self::rustc_serialize::base64::{ToBase64, Config, CharacterSet, Newline};
+ use self::rustc_serialize::json::Json;
+
+ use webdriver::command::NewSessionParameters;
+ use marionette::MarionetteHandler;
+ use super::FirefoxOptions;
+
+ fn example_profile() -> Json {
+ let mut profile_data = Vec::with_capacity(1024);
+ let mut profile = File::open("src/tests/profile.zip").unwrap();
+ profile.read_to_end(&mut profile_data).unwrap();
+ let base64_config = Config {
+ char_set: CharacterSet::Standard,
+ newline: Newline::LF,
+ pad: true,
+ line_length: None
+ };
+ Json::String(profile_data.to_base64(base64_config))
+ }
+
+ fn capabilities() -> NewSessionParameters {
+ let desired: BTreeMap<String, Json> = BTreeMap::new();
+ let required: BTreeMap<String, Json> = BTreeMap::new();
+ NewSessionParameters {
+ desired: desired,
+ required: required
+ }
+ }
+
+ #[test]
+ fn test_profile() {
+ let encoded_profile = example_profile();
+
+ let mut capabilities = capabilities();
+ let mut firefox_options: BTreeMap<String, Json> = BTreeMap::new();
+ firefox_options.insert("profile".into(), encoded_profile);
+ capabilities.required.insert("moz:firefoxOptions".into(), Json::Object(firefox_options));
+
+ let options = FirefoxOptions::from_capabilities(&mut capabilities).unwrap();
+ let mut profile = options.profile.unwrap();
+ let prefs = profile.user_prefs().unwrap();
+
+ println!("{:?}",prefs.prefs);
+
+ assert_eq!(prefs.get("startup.homepage_welcome_url"),
+ Some(&Pref::new("data:text/html,PASS")));
+ }
+
+ #[test]
+ fn test_prefs() {
+ let encoded_profile = example_profile();
+
+ let mut capabilities = capabilities();
+ let mut firefox_options: BTreeMap<String, Json> = BTreeMap::new();
+ firefox_options.insert("profile".into(), encoded_profile);
+ let mut prefs: BTreeMap<String, Json> = BTreeMap::new();
+ prefs.insert("browser.display.background_color".into(), Json::String("#00ff00".into()));
+ firefox_options.insert("prefs".into(), Json::Object(prefs));
+ capabilities.required.insert("moz:firefoxOptions".into(), Json::Object(firefox_options));
+
+
+ let options = FirefoxOptions::from_capabilities(&mut capabilities).unwrap();
+ let mut profile = options.profile.unwrap();
+
+ let handler = MarionetteHandler::new(Default::default());
+ handler.set_prefs(2828, &mut profile, true, options.prefs).unwrap();
+
+ let prefs_set = profile.user_prefs().unwrap();
+ println!("{:?}",prefs_set.prefs);
+ 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.defaultPrefs.port"),
+ Some(&Pref::new(2828)));
+ }
+}