Bug 1477474 - Return moz:geckodriverVersion on session creation. r=automatedtester
authorAndreas Tolfsen <ato@sny.no>
Sat, 21 Jul 2018 14:09:53 +0100
changeset 821992 0a9411bc7b5dcfac1c3e2deacaa8d0b65d5b3a85
parent 821991 eacc31a62f16f7585f847981e0b48269db66ec5f
child 821993 666d7dc7a32cbcacb8ef4b0120cf849a7ca8a911
child 822068 54f69f217483467dbd22e02ab4a98d8d8bc0ded8
push id117242
push userrwood@mozilla.com
push dateTue, 24 Jul 2018 13:33:52 +0000
reviewersautomatedtester
bugs1477474
milestone63.0a1
Bug 1477474 - Return moz:geckodriverVersion on session creation. r=automatedtester This introduces a new extension capability, moz:geckodriverVersion, that will be returned on session creation with the geckodriver version number.
testing/geckodriver/src/build.rs
testing/geckodriver/src/main.rs
testing/geckodriver/src/marionette.rs
new file mode 100644
--- /dev/null
+++ b/testing/geckodriver/src/build.rs
@@ -0,0 +1,41 @@
+use std::fmt;
+
+use rustc_serialize::json::{Json};
+
+include!(concat!(env!("OUT_DIR"), "/build-info.rs"));
+
+pub struct BuildInfo;
+
+impl BuildInfo {
+    pub fn version() -> &'static str {
+        crate_version!()
+    }
+
+    pub fn hash() -> Option<&'static str> {
+        COMMIT_HASH
+    }
+
+    pub fn date() -> Option<&'static str> {
+        COMMIT_DATE
+    }
+}
+
+impl fmt::Display for BuildInfo {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", BuildInfo::version())?;
+        match (BuildInfo::hash(), BuildInfo::date()) {
+            (Some(hash), Some(date)) => write!(f, " ({} {})", hash, date)?,
+            (Some(hash), None) => write!(f, " ({})", hash)?,
+            _ => {}
+        }
+        Ok(())
+    }
+}
+
+//std::convert::From<&str>` is not implemented for `rustc_serialize::json::Json
+
+impl Into<Json> for BuildInfo {
+    fn into(self) -> Json {
+        Json::String(BuildInfo::version().to_string())
+    }
+}
--- a/testing/geckodriver/src/main.rs
+++ b/testing/geckodriver/src/main.rs
@@ -11,77 +11,49 @@ extern crate regex;
 extern crate rustc_serialize;
 extern crate uuid;
 extern crate zip;
 extern crate webdriver;
 
 #[macro_use]
 extern crate log;
 
-use std::fmt;
 use std::io::Write;
 use std::net::{IpAddr, SocketAddr};
 use std::path::PathBuf;
 use std::str::FromStr;
 
 use clap::{App, Arg};
 
 macro_rules! try_opt {
     ($expr:expr, $err_type:expr, $err_msg:expr) => ({
         match $expr {
             Some(x) => x,
             None => return Err(WebDriverError::new($err_type, $err_msg))
         }
     })
 }
 
+mod build;
 mod logging;
 mod prefs;
 mod marionette;
 mod capabilities;
 
+use build::BuildInfo;
 use marionette::{MarionetteHandler, MarionetteSettings, extension_routes};
 
-include!(concat!(env!("OUT_DIR"), "/build-info.rs"));
-
 type ProgramResult = std::result::Result<(), (ExitCode, String)>;
 
 enum ExitCode {
     Ok = 0,
     Usage = 64,
     Unavailable = 69,
 }
 
-struct BuildInfo;
-impl BuildInfo {
-    pub fn version() -> &'static str {
-        crate_version!()
-    }
-
-    pub fn hash() -> Option<&'static str> {
-        COMMIT_HASH
-    }
-
-    pub fn date() -> Option<&'static str> {
-        COMMIT_DATE
-    }
-}
-
-impl fmt::Display for BuildInfo {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BuildInfo::version())?;
-        match (BuildInfo::hash(), BuildInfo::date()) {
-            (Some(hash), Some(date)) => write!(f, " ({} {})", hash, date)?,
-            (Some(hash), None) => write!(f, " ({})", hash)?,
-            _ => {}
-        }
-        Ok(())
-    }
-}
-
 fn print_version() {
     println!("geckodriver {}", BuildInfo);
     println!("");
     println!("The source code of this program is available from");
     println!("testing/geckodriver in https://hg.mozilla.org/mozilla-central.");
     println!("");
     println!("This program is subject to the terms of the Mozilla Public License 2.0.");
     println!("You can obtain a copy of the license at https://mozilla.org/MPL/2.0/.");
--- a/testing/geckodriver/src/marionette.rs
+++ b/testing/geckodriver/src/marionette.rs
@@ -45,16 +45,17 @@ use webdriver::command::{
 use webdriver::response::{CloseWindowResponse, Cookie, CookieResponse, CookiesResponse,
                           ElementRectResponse, NewSessionResponse, TimeoutsResponse,
                           ValueResponse, WebDriverResponse, WindowRectResponse};
 use webdriver::common::{Date, ELEMENT_KEY, FrameId, FRAME_KEY, Nullable, WebElement, WINDOW_KEY};
 use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult};
 use webdriver::server::{WebDriverHandler, Session};
 use webdriver::httpapi::{WebDriverExtensionRoute};
 
+use build::BuildInfo;
 use capabilities::{FirefoxCapabilities, FirefoxOptions};
 use logging;
 use prefs;
 
 // localhost may be routed to the IPv6 stack on certain systems,
 // and nsIServerSocket in Marionette only supports IPv4
 const DEFAULT_HOST: &'static str = "127.0.0.1";
 
@@ -890,25 +891,27 @@ impl MarionetteSession {
                              "Failed to find sessionId field").as_string(),
                     ErrorStatus::InvalidSessionId,
                     "sessionId was not a string");
 
                 if session_id.starts_with("{") && session_id.ends_with("}") {
                     session_id = &session_id[1..session_id.len()-1];
                 }
 
-                let capabilities = try_opt!(
+                let mut capabilities = try_opt!(
                     try_opt!(resp.result.find("capabilities"),
                              ErrorStatus::UnknownError,
                              "Failed to find capabilities field").as_object(),
                     ErrorStatus::UnknownError,
-                    "capabiltites field was not an Object");
+                    "capabilities field is not an object").clone();
+
+                capabilities.insert("moz:geckodriverVersion".into(), BuildInfo.into());
 
                 WebDriverResponse::NewSession(NewSessionResponse::new(
-                    session_id.to_string(), Json::Object(capabilities.clone())))
+                    session_id.to_string(), Json::Object(capabilities)))
             },
             DeleteSession => {
                 WebDriverResponse::DeleteSession
             },
             Extension(ref extension) => {
                 match extension {
                     &GeckoExtensionCommand::GetContext => {
                         let value = try_opt!(resp.result.find("value"),