geckodriver: Connect between geckodriver and marionette on a random port. (#112)

This allows running multiple sessions without needing to reuse the
same port.

Source-Repo: https://github.com/mozilla/geckodriver
Source-Revision: 4d9e5b321e2665cb94f59fab16798a210020dc4b

committer: GitHub <noreply@github.com>

--HG--
extra : rebase_source : 2b43771675aa3b476ecad2068e94fdbe82fc9a6b
This commit is contained in:
jgraham 2016-06-27 21:24:22 +01:00
Родитель d9161df980
Коммит 6e1cfa655d
2 изменённых файлов: 28 добавлений и 15 удалений

Просмотреть файл

@ -19,7 +19,7 @@ use std::net::{SocketAddr, IpAddr};
use std::path::Path;
use std::str::FromStr;
use argparse::{ArgumentParser, IncrBy, StoreTrue, Store};
use argparse::{ArgumentParser, IncrBy, StoreTrue, Store, StoreOption};
use webdriver::server::start;
use marionette::{MarionetteHandler, BrowserLauncher, LogLevel, MarionetteSettings, extension_routes};
@ -46,7 +46,7 @@ struct Options {
binary: String,
webdriver_host: String,
webdriver_port: u16,
marionette_port: u16,
marionette_port: Option<u16>,
connect_existing: bool,
e10s: bool,
log_level: String,
@ -59,7 +59,7 @@ fn parse_args() -> Options {
binary: "".to_owned(),
webdriver_host: "127.0.0.1".to_owned(),
webdriver_port: 4444u16,
marionette_port: 2828u16,
marionette_port: None,
connect_existing: false,
e10s: false,
log_level: "".to_owned(),
@ -81,7 +81,7 @@ fn parse_args() -> Options {
.add_option(&["--webdriver-port"], Store,
"Port to run webdriver on");
parser.refer(&mut opts.marionette_port)
.add_option(&["--marionette-port"], Store,
.add_option(&["--marionette-port"], StoreOption,
"Port to run marionette on");
parser.refer(&mut opts.connect_existing)
.add_option(&["--connect-existing"], StoreTrue,
@ -205,6 +205,8 @@ mod tests {
use mozprofile::preferences::Pref;
use std::io::Read;
const MARIONETTE_DEFAULT_PORT: u16 = 2828;
#[test]
fn test_profile() {
let mut profile_data = Vec::with_capacity(1024);
@ -227,7 +229,7 @@ mod tests {
};
let settings = MarionetteSettings {
port: 2828,
port: None,
launcher: BrowserLauncher::None,
e10s: false,
log_level: None,
@ -235,7 +237,7 @@ mod tests {
let handler = MarionetteHandler::new(settings);
let mut gecko_profile = handler.load_profile(&capabilities).unwrap().unwrap();
handler.set_prefs(&mut gecko_profile, true).unwrap();
handler.set_prefs(MARIONETTE_DEFAULT_PORT, &mut gecko_profile, true).unwrap();
let prefs = gecko_profile.user_prefs().unwrap();

Просмотреть файл

@ -16,7 +16,7 @@ use std::io::ErrorKind;
use std::io::Result as IoResult;
use std::io::prelude::*;
use std::io;
use std::net::TcpStream;
use std::net::{TcpListener, TcpStream};
use std::path::{Path, PathBuf};
use std::sync::Mutex;
use std::thread::sleep;
@ -277,7 +277,7 @@ impl FromStr for LogLevel {
}
pub struct MarionetteSettings {
pub port: u16,
pub port: Option<u16>,
pub launcher: BrowserLauncher,
/// Enable or disable Electrolysis, or multi-processing, in Gecko.
@ -293,7 +293,7 @@ pub struct MarionetteHandler {
connection: Mutex<Option<MarionetteConnection>>,
launcher: BrowserLauncher,
browser: Option<FirefoxRunner>,
port: u16,
port: Option<u16>,
e10s: bool,
log_level: Option<LogLevel>,
}
@ -315,7 +315,11 @@ impl MarionetteHandler {
debug!("create_connection");
let profile = try!(self.load_profile(capabilities));
let args = try!(self.load_browser_args(capabilities));
match self.start_browser(profile, args) {
let port = match self.port {
Some(x) => x,
None => try!(get_free_port())
};
match self.start_browser(port, profile, args) {
Err(e) => {
return Err(WebDriverError::new(ErrorStatus::UnknownError,
e.description().to_owned()));
@ -323,7 +327,7 @@ impl MarionetteHandler {
Ok(_) => {}
}
debug!("Creating connection");
let mut connection = MarionetteConnection::new(self.port, session_id.clone());
let mut connection = MarionetteConnection::new(port, session_id.clone());
debug!("Starting marionette connection");
try!(connection.connect());
debug!("Marionette connection started");
@ -331,7 +335,7 @@ impl MarionetteHandler {
Ok(())
}
fn start_browser(&mut self, profile: Option<Profile>, args: Option<Vec<String>>) -> Result<(), RunnerError> {
fn start_browser(&mut self, port: u16, profile: Option<Profile>, args: Option<Vec<String>>) -> Result<(), RunnerError> {
let custom_profile = profile.is_some();
match self.launcher {
@ -340,7 +344,7 @@ impl MarionetteHandler {
if let Some(cmd_args) = args {
runner.args().extend(cmd_args);
};
try!(self.set_prefs(&mut runner.profile, custom_profile));
try!(self.set_prefs(port, &mut runner.profile, custom_profile));
try!(runner.start());
self.browser = Some(runner);
@ -353,10 +357,10 @@ impl MarionetteHandler {
Ok(())
}
pub fn set_prefs(&self, profile: &mut Profile, custom_profile: bool)
pub fn set_prefs(&self, port: u16, profile: &mut Profile, custom_profile: bool)
-> Result<(), RunnerError> {
let prefs = try!(profile.user_prefs());
prefs.insert("marionette.defaultPrefs.port", Pref::new(self.port as i64));
prefs.insert("marionette.defaultPrefs.port", Pref::new(port as i64));
prefs.insert_slice(&FIREFOX_REQUIRED_PREFERENCES[..]);
if !custom_profile {
@ -1085,6 +1089,12 @@ impl ToJson for MarionetteError {
}
}
fn get_free_port() -> IoResult<u16> {
TcpListener::bind(&("localhost", 0))
.and_then(|stream| stream.local_addr())
.map(|x| x.port())
}
pub struct MarionetteConnection {
port: u16,
stream: Option<TcpStream>,
@ -1105,6 +1115,7 @@ impl MarionetteConnection {
let poll_interval = 100; // ms
let poll_attempts = timeout / poll_interval;
let mut poll_attempt = 0;
info!("Connecting to Marionette on localhost:{}", self.port);
loop {
match TcpStream::connect(&("localhost", self.port)) {
Ok(stream) => {