webdriver_server: associate timeouts with session

The WebDriver timeout configuration durations should be associated with
the session so that they do not bleed across sessions.  Since they are
currently stored on the WebDriverHandler, a call to the SetTimeouts
command will cause them to affect the subsequent session.
This commit is contained in:
Andreas Tolfsen 2017-01-26 18:40:03 +00:00
parent 88cd8a3cf0
commit e87c275de0

View file

@ -96,18 +96,39 @@ pub fn start_server(port: u16, constellation_chan: Sender<ConstellationMsg>) {
}).expect("Thread spawning failed"); }).expect("Thread spawning failed");
} }
/// Represents the current WebDriver session and holds relevant session state.
struct WebDriverSession { struct WebDriverSession {
id: Uuid, id: Uuid,
frame_id: Option<FrameId> frame_id: Option<FrameId>,
/// Time to wait for injected scripts to run before interrupting them.
script_timeout: u32,
/// Time to wait for a page to finish loading upon navigation.
load_timeout: u32,
/// Time to wait for the element location strategy when retrieving elements, and when
/// waiting for an element to become interactable.
implicit_wait_timeout: u32,
}
impl WebDriverSession {
pub fn new() -> WebDriverSession {
WebDriverSession {
id: Uuid::new_v4(),
frame_id: None,
script_timeout: 30_000,
load_timeout: 300_000,
implicit_wait_timeout: 0,
}
}
} }
struct Handler { struct Handler {
session: Option<WebDriverSession>, session: Option<WebDriverSession>,
constellation_chan: Sender<ConstellationMsg>, constellation_chan: Sender<ConstellationMsg>,
script_timeout: u32,
load_timeout: u32,
resize_timeout: u32, resize_timeout: u32,
implicit_wait_timeout: u32
} }
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
@ -230,24 +251,12 @@ impl ToJson for SetPrefsParameters {
} }
} }
impl WebDriverSession {
pub fn new() -> WebDriverSession {
WebDriverSession {
id: Uuid::new_v4(),
frame_id: None
}
}
}
impl Handler { impl Handler {
pub fn new(constellation_chan: Sender<ConstellationMsg>) -> Handler { pub fn new(constellation_chan: Sender<ConstellationMsg>) -> Handler {
Handler { Handler {
session: None, session: None,
constellation_chan: constellation_chan, constellation_chan: constellation_chan,
script_timeout: 30_000,
load_timeout: 300_000,
resize_timeout: 500, resize_timeout: 500,
implicit_wait_timeout: 0
} }
} }
@ -355,19 +364,25 @@ impl Handler {
fn wait_for_load(&self, fn wait_for_load(&self,
sender: IpcSender<LoadStatus>, sender: IpcSender<LoadStatus>,
receiver: IpcReceiver<LoadStatus>) -> WebDriverResult<WebDriverResponse> { receiver: IpcReceiver<LoadStatus>)
let timeout = self.load_timeout; -> WebDriverResult<WebDriverResponse> {
let session = try!(self.session
.as_ref()
.ok_or(WebDriverError::new(ErrorStatus::SessionNotCreated, "")));
let timeout = session.load_timeout;
let timeout_chan = sender; let timeout_chan = sender;
thread::spawn(move || { thread::spawn(move || {
thread::sleep(Duration::from_millis(timeout as u64)); thread::sleep(Duration::from_millis(timeout as u64));
let _ = timeout_chan.send(LoadStatus::LoadTimeout); let _ = timeout_chan.send(LoadStatus::LoadTimeout);
}); });
//Wait to get a load event // wait to get a load event
match receiver.recv().unwrap() { match receiver.recv().unwrap() {
LoadStatus::LoadComplete => Ok(WebDriverResponse::Void), LoadStatus::LoadComplete => Ok(WebDriverResponse::Void),
LoadStatus::LoadTimeout => Err(WebDriverError::new(ErrorStatus::Timeout, LoadStatus::LoadTimeout => {
"Load timed out")) Err(WebDriverError::new(ErrorStatus::Timeout, "Load timed out"))
}
} }
} }
@ -683,16 +698,25 @@ impl Handler {
} }
} }
fn handle_set_timeouts(&mut self, parameters: &TimeoutsParameters) -> WebDriverResult<WebDriverResponse> { fn handle_set_timeouts(&mut self,
//TODO: this conversion is crazy, spec should limit these to u32 and check upstream parameters: &TimeoutsParameters)
-> WebDriverResult<WebDriverResponse> {
let mut session = try!(self.session
.as_mut()
.ok_or(WebDriverError::new(ErrorStatus::SessionNotCreated, "")));
// TODO(ato): Conversation is wrong. The script timeout can be null, and the numeric
// values should be limited to u32 in the standard.
let value = parameters.ms as u32; let value = parameters.ms as u32;
match &parameters.type_[..] { match &parameters.type_[..] {
"implicit" => self.implicit_wait_timeout = value, "script" => session.script_timeout = value,
"page load" => self.load_timeout = value, "page load" => session.load_timeout = value,
"script" => self.script_timeout = value, "implicit" => session.implicit_wait_timeout = value,
x => return Err(WebDriverError::new(ErrorStatus::InvalidSelector, x => {
return Err(WebDriverError::new(ErrorStatus::InvalidSelector,
format!("Unknown timeout type {}", x))) format!("Unknown timeout type {}", x)))
} }
}
Ok(WebDriverResponse::Void) Ok(WebDriverResponse::Void)
} }
@ -712,13 +736,19 @@ impl Handler {
} }
fn handle_execute_async_script(&self, fn handle_execute_async_script(&self,
parameters: &JavascriptCommandParameters) -> WebDriverResult<WebDriverResponse> { parameters: &JavascriptCommandParameters)
-> WebDriverResult<WebDriverResponse> {
let session = try!(self.session
.as_ref()
.ok_or(WebDriverError::new(ErrorStatus::SessionNotCreated, "")));
let func_body = &parameters.script; let func_body = &parameters.script;
let args_string = "window.webdriverCallback"; let args_string = "window.webdriverCallback";
let script = format!( let script = format!("setTimeout(webdriverTimeout, {}); (function(callback) {{ {} }})({})",
"setTimeout(webdriverTimeout, {}); (function(callback) {{ {} }})({})", session.script_timeout,
self.script_timeout, func_body, args_string); func_body,
args_string);
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
let command = WebDriverScriptCommand::ExecuteAsyncScript(script, sender); let command = WebDriverScriptCommand::ExecuteAsyncScript(script, sender);