OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/test/webdriver/session_manager.h" | 5 #include "chrome/test/webdriver/session_manager.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/message_loop_proxy.h" | 12 #include "base/message_loop_proxy.h" |
13 #include "base/process.h" | 13 #include "base/process.h" |
14 #include "base/process_util.h" | 14 #include "base/process_util.h" |
| 15 #include "base/scoped_ptr.h" |
15 #include "base/stringprintf.h" | 16 #include "base/stringprintf.h" |
| 17 #include "base/string_number_conversions.h" |
16 #include "base/string_util.h" | 18 #include "base/string_util.h" |
17 #include "base/json/json_reader.h" | 19 #include "base/json/json_reader.h" |
18 #include "base/json/json_writer.h" | 20 #include "base/json/json_writer.h" |
19 #include "base/test/test_timeouts.h" | 21 #include "base/test/test_timeouts.h" |
20 #include "base/utf_string_conversions.h" | 22 #include "base/utf_string_conversions.h" |
21 #include "chrome/app/chrome_command_ids.h" | 23 #include "chrome/app/chrome_command_ids.h" |
22 #include "chrome/common/chrome_constants.h" | 24 #include "chrome/common/chrome_constants.h" |
23 #include "chrome/common/chrome_switches.h" | 25 #include "chrome/common/chrome_switches.h" |
24 #include "chrome/test/test_launcher_utils.h" | 26 #include "chrome/test/test_launcher_utils.h" |
| 27 #include "chrome/test/webdriver/session_manager.h" |
25 #include "chrome/test/webdriver/utility_functions.h" | 28 #include "chrome/test/webdriver/utility_functions.h" |
26 #include "chrome/test/webdriver/webdriver_key_converter.h" | 29 #include "chrome/test/webdriver/webdriver_key_converter.h" |
27 #include "googleurl/src/gurl.h" | 30 #include "googleurl/src/gurl.h" |
28 #include "third_party/webdriver/atoms.h" | 31 #include "third_party/webdriver/atoms.h" |
29 | 32 |
30 namespace webdriver { | 33 namespace webdriver { |
31 | 34 |
32 Session::Session(const std::string& id) | 35 Session::Session() |
33 : thread_(id.c_str()), | 36 : id_(GenerateRandomID()), |
34 id_(id), | 37 thread_(id_.c_str()), |
35 window_num_(0), | |
36 implicit_wait_(0), | 38 implicit_wait_(0), |
37 current_frame_xpath_("") { | 39 current_frame_xpath_(""), |
| 40 current_window_id_(0) { |
| 41 SessionManager::GetInstance()->Add(this); |
38 } | 42 } |
39 | 43 |
40 Session::~Session() {} | 44 Session::~Session() { |
| 45 SessionManager::GetInstance()->Remove(id_); |
| 46 } |
41 | 47 |
42 bool Session::Init() { | 48 bool Session::Init() { |
43 if (!thread_.Start()) { | 49 bool success = false; |
| 50 if (thread_.Start()) { |
| 51 RunSessionTask(NewRunnableMethod( |
| 52 this, |
| 53 &Session::InitOnSessionThread, |
| 54 &success)); |
| 55 } else { |
44 LOG(ERROR) << "Cannot start session thread"; | 56 LOG(ERROR) << "Cannot start session thread"; |
45 return false; | |
46 } | 57 } |
47 | 58 if (!success) |
48 bool success = false; | 59 delete this; |
49 RunSessionTask(NewRunnableMethod( | |
50 this, | |
51 &Session::InitOnSessionThread, | |
52 &success)); | |
53 return success; | 60 return success; |
54 } | 61 } |
55 | 62 |
56 void Session::Terminate() { | 63 void Session::Terminate() { |
57 RunSessionTask(NewRunnableMethod( | 64 RunSessionTask(NewRunnableMethod( |
58 this, | 65 this, |
59 &Session::TerminateOnSessionThread)); | 66 &Session::TerminateOnSessionThread)); |
| 67 delete this; |
60 } | 68 } |
61 | 69 |
62 ErrorCode Session::ExecuteScript(const std::string& script, | 70 ErrorCode Session::ExecuteScript(int window_id, |
| 71 const std::string& frame_xpath, |
| 72 const std::string& script, |
63 const ListValue* const args, | 73 const ListValue* const args, |
64 Value** value) { | 74 Value** value) { |
65 std::string args_as_json; | 75 std::string args_as_json; |
66 base::JSONWriter::Write(static_cast<const Value* const>(args), | 76 base::JSONWriter::Write(static_cast<const Value* const>(args), |
67 /*pretty_print=*/false, | 77 /*pretty_print=*/false, |
68 &args_as_json); | 78 &args_as_json); |
69 | 79 |
70 // Every injected script is fed through the executeScript atom. This atom | 80 // Every injected script is fed through the executeScript atom. This atom |
71 // will catch any errors that are thrown and convert them to the | 81 // will catch any errors that are thrown and convert them to the |
72 // appropriate JSON structure. | 82 // appropriate JSON structure. |
73 std::string jscript = base::StringPrintf( | 83 std::string jscript = base::StringPrintf( |
74 "window.domAutomationController.send((%s).apply(null," | 84 "window.domAutomationController.send((%s).apply(null," |
75 "[function(){%s\n},%s,true]));", | 85 "[function(){%s\n},%s,true]));", |
76 atoms::EXECUTE_SCRIPT, script.c_str(), args_as_json.c_str()); | 86 atoms::EXECUTE_SCRIPT, script.c_str(), args_as_json.c_str()); |
77 | 87 |
78 // Should we also log the script that's being executed? It could be several KB | 88 // Should we also log the script that's being executed? It could be several KB |
79 // in size and will add lots of noise to the logs. | 89 // in size and will add lots of noise to the logs. |
80 VLOG(1) << "Executing script in frame: " << current_frame_xpath_; | 90 VLOG(1) << "Executing script in frame: " << current_frame_xpath_; |
81 | 91 |
82 std::string result; | 92 std::string result; |
83 bool success; | 93 bool success = false; |
84 RunSessionTask(NewRunnableMethod( | 94 RunSessionTask(NewRunnableMethod( |
85 automation_.get(), | 95 automation_.get(), |
86 &Automation::ExecuteScript, | 96 &Automation::ExecuteScript, |
87 current_frame_xpath_, | 97 window_id, |
| 98 frame_xpath, |
88 jscript, | 99 jscript, |
89 &result, | 100 &result, |
90 &success)); | 101 &success)); |
91 if (!success) { | 102 if (!success) { |
| 103 LOG(ERROR) << "Automation failed to execute script"; |
92 *value = Value::CreateStringValue( | 104 *value = Value::CreateStringValue( |
93 "Unknown internal script execution failure"); | 105 "Unknown internal script execution failure"); |
94 return kUnknownError; | 106 return kUnknownError; |
95 } | 107 } |
96 | 108 |
97 VLOG(1) << "...script result: " << result; | 109 VLOG(1) << "...script result: " << result; |
98 scoped_ptr<Value> r(base::JSONReader::ReadAndReturnError( | 110 scoped_ptr<Value> r(base::JSONReader::ReadAndReturnError( |
99 result, true, NULL, NULL)); | 111 result, true, NULL, NULL)); |
100 if (!r.get()) { | 112 if (!r.get()) { |
| 113 LOG(ERROR) << "Failed to parse script result"; |
101 *value = Value::CreateStringValue( | 114 *value = Value::CreateStringValue( |
102 "Internal script execution error: failed to parse script result"); | 115 "Internal script execution error: failed to parse script result"); |
103 return kUnknownError; | 116 return kUnknownError; |
104 } | 117 } |
105 | 118 |
106 if (r->GetType() != Value::TYPE_DICTIONARY) { | 119 if (r->GetType() != Value::TYPE_DICTIONARY) { |
| 120 LOG(ERROR) << "Execute script returned non-dictionary type"; |
107 std::ostringstream stream; | 121 std::ostringstream stream; |
108 stream << "Internal script execution error: script result must be a " | 122 stream << "Internal script execution error: script result must be a " |
109 << print_valuetype(Value::TYPE_DICTIONARY) << ", but was " | 123 << print_valuetype(Value::TYPE_DICTIONARY) << ", but was " |
110 << print_valuetype(r->GetType()) << ": " << result; | 124 << print_valuetype(r->GetType()) << ": " << result; |
111 *value = Value::CreateStringValue(stream.str()); | 125 *value = Value::CreateStringValue(stream.str()); |
112 return kUnknownError; | 126 return kUnknownError; |
113 } | 127 } |
114 | 128 |
115 DictionaryValue* result_dict = static_cast<DictionaryValue*>(r.get()); | 129 DictionaryValue* result_dict = static_cast<DictionaryValue*>(r.get()); |
116 | 130 |
117 Value* tmp; | 131 Value* tmp; |
118 if (result_dict->Get("value", &tmp)) { | 132 if (result_dict->Get("value", &tmp)) { |
119 // result_dict owns the returned value, so we need to make a copy. | 133 // result_dict owns the returned value, so we need to make a copy. |
120 *value = tmp->DeepCopy(); | 134 *value = tmp->DeepCopy(); |
121 } else { | 135 } else { |
122 // "value" was not defined in the returned dictionary, set to null. | 136 // "value" was not defined in the returned dictionary, set to null. |
123 *value = Value::CreateNullValue(); | 137 *value = Value::CreateNullValue(); |
124 } | 138 } |
125 | 139 |
126 int status; | 140 int status; |
127 if (!result_dict->GetInteger("status", &status)) { | 141 if (!result_dict->GetInteger("status", &status)) { |
128 NOTREACHED() << "...script did not return a status flag."; | 142 NOTREACHED() << "...script did not return a status flag."; |
129 } | 143 } |
130 return static_cast<ErrorCode>(status); | 144 return static_cast<ErrorCode>(status); |
131 } | 145 } |
132 | 146 |
| 147 ErrorCode Session::ExecuteScript(const std::string& script, |
| 148 const ListValue* const args, |
| 149 Value** value) { |
| 150 return ExecuteScript( |
| 151 current_window_id_, current_frame_xpath_, script, args, value); |
| 152 } |
| 153 |
133 ErrorCode Session::SendKeys(DictionaryValue* element, const string16& keys) { | 154 ErrorCode Session::SendKeys(DictionaryValue* element, const string16& keys) { |
134 ListValue args; | 155 ListValue args; |
135 args.Append(element); | 156 args.Append(element); |
136 // TODO(jleyba): Update this to use the correct atom. | 157 // TODO(jleyba): Update this to use the correct atom. |
137 std::string script = "document.activeElement.blur();arguments[0].focus();"; | 158 std::string script = "document.activeElement.blur();arguments[0].focus();"; |
138 Value* unscoped_result = NULL; | 159 Value* unscoped_result = NULL; |
139 ErrorCode code = ExecuteScript(script, &args, &unscoped_result); | 160 ErrorCode code = ExecuteScript(script, &args, &unscoped_result); |
140 scoped_ptr<Value> result(unscoped_result); | 161 scoped_ptr<Value> result(unscoped_result); |
141 if (code != kSuccess) | 162 if (code != kSuccess) { |
| 163 LOG(ERROR) << "Failed to focus element before sending keys"; |
142 return code; | 164 return code; |
| 165 } |
143 | 166 |
144 bool success = false; | 167 bool success = false; |
145 RunSessionTask(NewRunnableMethod( | 168 RunSessionTask(NewRunnableMethod( |
146 this, | 169 this, |
147 &Session::SendKeysOnSessionThread, | 170 &Session::SendKeysOnSessionThread, |
148 keys, | 171 keys, |
149 &success)); | 172 &success)); |
150 if (!success) | 173 if (!success) |
151 return kUnknownError; | 174 return kUnknownError; |
152 return kSuccess; | 175 return kSuccess; |
153 } | 176 } |
154 | 177 |
155 bool Session::NavigateToURL(const std::string& url) { | 178 bool Session::NavigateToURL(const std::string& url) { |
156 bool success = false; | 179 bool success = false; |
157 RunSessionTask(NewRunnableMethod( | 180 RunSessionTask(NewRunnableMethod( |
158 automation_.get(), | 181 automation_.get(), |
159 &Automation::NavigateToURL, | 182 &Automation::NavigateToURL, |
| 183 current_window_id_, |
160 url, | 184 url, |
161 &success)); | 185 &success)); |
162 return success; | 186 return success; |
163 } | 187 } |
164 | 188 |
165 bool Session::GoForward() { | 189 bool Session::GoForward() { |
166 bool success = false; | 190 bool success = false; |
167 RunSessionTask(NewRunnableMethod( | 191 RunSessionTask(NewRunnableMethod( |
168 automation_.get(), | 192 automation_.get(), |
169 &Automation::GoForward, | 193 &Automation::GoForward, |
| 194 current_window_id_, |
170 &success)); | 195 &success)); |
171 return success; | 196 return success; |
172 } | 197 } |
173 | 198 |
174 bool Session::GoBack() { | 199 bool Session::GoBack() { |
175 bool success = false; | 200 bool success = false; |
176 RunSessionTask(NewRunnableMethod( | 201 RunSessionTask(NewRunnableMethod( |
177 automation_.get(), | 202 automation_.get(), |
178 &Automation::GoBack, | 203 &Automation::GoBack, |
| 204 current_window_id_, |
179 &success)); | 205 &success)); |
180 return success; | 206 return success; |
181 } | 207 } |
182 | 208 |
183 bool Session::Reload() { | 209 bool Session::Reload() { |
184 bool success = false; | 210 bool success = false; |
185 RunSessionTask(NewRunnableMethod( | 211 RunSessionTask(NewRunnableMethod( |
186 automation_.get(), | 212 automation_.get(), |
187 &Automation::Reload, | 213 &Automation::Reload, |
| 214 current_window_id_, |
188 &success)); | 215 &success)); |
189 return success; | 216 return success; |
190 } | 217 } |
191 | 218 |
192 bool Session::GetURL(std::string* url) { | 219 bool Session::GetURL(std::string* url) { |
193 bool success = false; | 220 bool success = false; |
194 RunSessionTask(NewRunnableMethod( | 221 RunSessionTask(NewRunnableMethod( |
195 automation_.get(), | 222 automation_.get(), |
196 &Automation::GetURL, | 223 &Automation::GetURL, |
| 224 current_window_id_, |
197 url, | 225 url, |
198 &success)); | 226 &success)); |
199 return success; | 227 return success; |
200 } | 228 } |
201 | 229 |
202 bool Session::GetURL(GURL* gurl) { | 230 bool Session::GetURL(GURL* gurl) { |
203 bool success = false; | 231 bool success = false; |
204 RunSessionTask(NewRunnableMethod( | 232 RunSessionTask(NewRunnableMethod( |
205 automation_.get(), | 233 automation_.get(), |
206 &Automation::GetGURL, | 234 &Automation::GetGURL, |
| 235 current_window_id_, |
207 gurl, | 236 gurl, |
208 &success)); | 237 &success)); |
209 return success; | 238 return success; |
210 } | 239 } |
211 | 240 |
212 bool Session::GetTabTitle(std::string* tab_title) { | 241 bool Session::GetTabTitle(std::string* tab_title) { |
213 bool success = false; | 242 bool success = false; |
214 RunSessionTask(NewRunnableMethod( | 243 RunSessionTask(NewRunnableMethod( |
215 automation_.get(), | 244 automation_.get(), |
216 &Automation::GetTabTitle, | 245 &Automation::GetTabTitle, |
| 246 current_window_id_, |
217 tab_title, | 247 tab_title, |
218 &success)); | 248 &success)); |
219 return success; | 249 return success; |
220 } | 250 } |
221 | 251 |
222 bool Session::GetCookies(const GURL& url, std::string* cookies) { | 252 bool Session::GetCookies(const GURL& url, std::string* cookies) { |
223 bool success = false; | 253 bool success = false; |
224 RunSessionTask(NewRunnableMethod( | 254 RunSessionTask(NewRunnableMethod( |
225 automation_.get(), | 255 automation_.get(), |
226 &Automation::GetCookies, | 256 &Automation::GetCookies, |
| 257 current_window_id_, |
227 url, | 258 url, |
228 cookies, | 259 cookies, |
229 &success)); | 260 &success)); |
230 return success; | 261 return success; |
231 } | 262 } |
232 | 263 |
233 bool Session::GetCookieByName(const GURL& url, | 264 bool Session::GetCookieByName(const GURL& url, |
234 const std::string& cookie_name, | 265 const std::string& cookie_name, |
235 std::string* cookie) { | 266 std::string* cookie) { |
236 bool success = false; | 267 bool success = false; |
237 RunSessionTask(NewRunnableMethod( | 268 RunSessionTask(NewRunnableMethod( |
238 automation_.get(), | 269 automation_.get(), |
239 &Automation::GetCookieByName, | 270 &Automation::GetCookieByName, |
| 271 current_window_id_, |
240 url, | 272 url, |
241 cookie_name, | 273 cookie_name, |
242 cookie, | 274 cookie, |
243 &success)); | 275 &success)); |
244 return success; | 276 return success; |
245 } | 277 } |
246 | 278 |
247 bool Session::DeleteCookie(const GURL& url, const std::string& cookie_name) { | 279 bool Session::DeleteCookie(const GURL& url, const std::string& cookie_name) { |
248 bool success = false; | 280 bool success = false; |
249 RunSessionTask(NewRunnableMethod( | 281 RunSessionTask(NewRunnableMethod( |
250 automation_.get(), | 282 automation_.get(), |
251 &Automation::DeleteCookie, | 283 &Automation::DeleteCookie, |
| 284 current_window_id_, |
252 url, | 285 url, |
253 cookie_name, | 286 cookie_name, |
254 &success)); | 287 &success)); |
255 return success; | 288 return success; |
256 } | 289 } |
257 | 290 |
258 bool Session::SetCookie(const GURL& url, const std::string& cookie) { | 291 bool Session::SetCookie(const GURL& url, const std::string& cookie) { |
259 bool success = false; | 292 bool success = false; |
260 RunSessionTask(NewRunnableMethod( | 293 RunSessionTask(NewRunnableMethod( |
261 automation_.get(), | 294 automation_.get(), |
262 &Automation::SetCookie, | 295 &Automation::SetCookie, |
| 296 current_window_id_, |
263 url, | 297 url, |
264 cookie, | 298 cookie, |
265 &success)); | 299 &success)); |
266 return success; | 300 return success; |
267 } | 301 } |
268 | 302 |
| 303 bool Session::GetWindowIds(std::vector<int>* window_ids) { |
| 304 bool success = false; |
| 305 RunSessionTask(NewRunnableMethod( |
| 306 automation_.get(), |
| 307 &Automation::GetTabIds, |
| 308 window_ids, |
| 309 &success)); |
| 310 return success; |
| 311 } |
| 312 |
| 313 ErrorCode Session::SwitchToWindow(const std::string& name) { |
| 314 int switch_to_id = 0; |
| 315 int name_no = 0; |
| 316 if (base::StringToInt(name, &name_no)) { |
| 317 bool does_exist = false; |
| 318 RunSessionTask(NewRunnableMethod( |
| 319 automation_.get(), |
| 320 &Automation::DoesTabExist, |
| 321 name_no, |
| 322 &does_exist)); |
| 323 if (does_exist) |
| 324 switch_to_id = name_no; |
| 325 } |
| 326 |
| 327 if (!switch_to_id) { |
| 328 std::vector<int> window_ids; |
| 329 GetWindowIds(&window_ids); |
| 330 // See if any of the window names match |name|. |
| 331 for (size_t i = 0; i < window_ids.size(); ++i) { |
| 332 ListValue empty_list; |
| 333 Value* unscoped_name_value; |
| 334 std::string window_name; |
| 335 ErrorCode code = ExecuteScript(window_ids[i], |
| 336 "", |
| 337 "return window.name;", |
| 338 &empty_list, |
| 339 &unscoped_name_value); |
| 340 scoped_ptr<Value> name_value(unscoped_name_value); |
| 341 if (code == kSuccess && |
| 342 name_value->GetAsString(&window_name) && |
| 343 name == window_name) { |
| 344 switch_to_id = window_ids[i]; |
| 345 break; |
| 346 } |
| 347 } |
| 348 } |
| 349 |
| 350 if (!switch_to_id) |
| 351 return kNoSuchWindow; |
| 352 current_window_id_ = switch_to_id; |
| 353 current_frame_xpath_ = ""; |
| 354 return kSuccess; |
| 355 } |
| 356 |
| 357 ErrorCode Session::SwitchToFrameWithNameOrId(const std::string& name_or_id) { |
| 358 std::string script = |
| 359 "var arg = arguments[0];" |
| 360 "var xpath = '(/html/body//iframe|/html/frameset/frame)';" |
| 361 "var sub = function(s) { return s.replace(/\\$/g, arg); };" |
| 362 "xpath += sub('[@name=\"$\" or @id=\"$\"]');" |
| 363 "var frame = document.evaluate(xpath, document, null, " |
| 364 " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" |
| 365 "if (!frame) { return null; }" |
| 366 "xpath = frame.tagName == 'IFRAME' ? '/html/body//iframe'" |
| 367 " : '/html/frameset/frame';" |
| 368 "return xpath + sub('[@' + (frame.id == arg ? 'id' : 'name')" |
| 369 " + '=\"$\"]');"; |
| 370 ListValue args; |
| 371 args.Append(new StringValue(name_or_id)); |
| 372 return SwitchToFrameWithJavaScriptLocatedFrame(script, &args); |
| 373 } |
| 374 |
| 375 ErrorCode Session::SwitchToFrameWithIndex(int index) { |
| 376 // We cannot simply index into window.frames because we need to know the |
| 377 // tagName of the frameElement. If child frame N is from another domain, then |
| 378 // the following will run afoul of the same origin policy: |
| 379 // window.frames[N].frameElement; |
| 380 // Instead of indexing window.frames, we use a an XPath expression to index |
| 381 // into the list of all IFRAME and FRAME elements on the page - if we find |
| 382 // something, then that XPath expression can be used as the new frame's XPath. |
| 383 std::string script = |
| 384 "var index = '[' + (arguments[0] + 1) + ']';" |
| 385 "var xpath = '(/html/body//iframe|/html/frameset/frame)' + " |
| 386 " index;" |
| 387 "console.info('searching for frame by xpath: ' + xpath);" |
| 388 "var frame = document.evaluate(xpath, document, null, " |
| 389 "XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" |
| 390 "console.info(frame == null ? 'found nothing' : frame);" |
| 391 "return frame == null ? null : ((frame.tagName == 'IFRAME' ? " |
| 392 " '/html/body//iframe' : '/html/frameset/frame') + index);"; |
| 393 ListValue args; |
| 394 args.Append(Value::CreateIntegerValue(index)); |
| 395 return SwitchToFrameWithJavaScriptLocatedFrame(script, &args); |
| 396 } |
| 397 |
| 398 bool Session::CloseWindow() { |
| 399 bool success = false; |
| 400 RunSessionTask(NewRunnableMethod( |
| 401 automation_.get(), |
| 402 &Automation::CloseTab, |
| 403 current_window_id_, |
| 404 &success)); |
| 405 |
| 406 if (success) { |
| 407 std::vector<int> window_ids; |
| 408 if (!GetWindowIds(&window_ids) || window_ids.empty()) { |
| 409 // The automation connection will soon be closed, if not already, |
| 410 // because we supposedly just closed the last window. Terminate the |
| 411 // session. |
| 412 // TODO(kkania): This will cause us problems if GetWindowIds fails for a |
| 413 // reason other than the channel is disconnected. Look into having |
| 414 // |GetWindowIds| tell us if it just closed the last window. |
| 415 Terminate(); |
| 416 } |
| 417 } |
| 418 return success; |
| 419 } |
| 420 |
269 void Session::RunSessionTask(Task* task) { | 421 void Session::RunSessionTask(Task* task) { |
270 base::WaitableEvent done_event(false, false); | 422 base::WaitableEvent done_event(false, false); |
271 thread_.message_loop_proxy()->PostTask(FROM_HERE, NewRunnableMethod( | 423 thread_.message_loop_proxy()->PostTask(FROM_HERE, NewRunnableMethod( |
272 this, | 424 this, |
273 &Session::RunSessionTaskOnSessionThread, | 425 &Session::RunSessionTaskOnSessionThread, |
274 task, | 426 task, |
275 &done_event)); | 427 &done_event)); |
276 done_event.Wait(); | 428 done_event.Wait(); |
277 } | 429 } |
278 | 430 |
279 void Session::RunSessionTaskOnSessionThread(Task* task, | 431 void Session::RunSessionTaskOnSessionThread(Task* task, |
280 base::WaitableEvent* done_event) { | 432 base::WaitableEvent* done_event) { |
281 task->Run(); | 433 task->Run(); |
282 delete task; | 434 delete task; |
283 done_event->Signal(); | 435 done_event->Signal(); |
284 } | 436 } |
285 | 437 |
286 void Session::InitOnSessionThread(bool* success) { | 438 void Session::InitOnSessionThread(bool* success) { |
287 automation_.reset(new Automation()); | 439 automation_.reset(new Automation()); |
288 automation_->Init(success); | 440 automation_->Init(success); |
| 441 if (!*success) |
| 442 return; |
| 443 |
| 444 std::vector<int> tab_ids; |
| 445 automation_->GetTabIds(&tab_ids, success); |
| 446 if (!*success) { |
| 447 LOG(ERROR) << "Could not get tab ids"; |
| 448 return; |
| 449 } |
| 450 if (tab_ids.empty()) { |
| 451 LOG(ERROR) << "No tab ids after initialization"; |
| 452 *success = false; |
| 453 } else { |
| 454 current_window_id_ = tab_ids[0]; |
| 455 } |
289 } | 456 } |
290 | 457 |
291 void Session::TerminateOnSessionThread() { | 458 void Session::TerminateOnSessionThread() { |
292 automation_->Terminate(); | 459 if (automation_.get()) |
| 460 automation_->Terminate(); |
293 automation_.reset(); | 461 automation_.reset(); |
294 } | 462 } |
295 | 463 |
296 void Session::SendKeysOnSessionThread(const string16& keys, | 464 void Session::SendKeysOnSessionThread(const string16& keys, |
297 bool* success) { | 465 bool* success) { |
298 *success = true; | 466 *success = true; |
299 std::vector<WebKeyEvent> key_events; | 467 std::vector<WebKeyEvent> key_events; |
300 ConvertKeysToWebKeyEvents(keys, &key_events); | 468 ConvertKeysToWebKeyEvents(keys, &key_events); |
301 for (size_t i = 0; i < key_events.size(); ++i) { | 469 for (size_t i = 0; i < key_events.size(); ++i) { |
302 bool key_success = false; | 470 bool key_success = false; |
303 automation_->SendWebKeyEvent(key_events[i], &key_success); | 471 automation_->SendWebKeyEvent( |
| 472 current_window_id_, key_events[i], &key_success); |
304 if (!key_success) { | 473 if (!key_success) { |
305 LOG(ERROR) << "Failed to send key event. Event details:\n" | 474 LOG(ERROR) << "Failed to send key event. Event details:\n" |
306 << "Type: " << key_events[i].type << "\n" | 475 << "Type: " << key_events[i].type << "\n" |
307 << "KeyCode: " << key_events[i].key_code << "\n" | 476 << "KeyCode: " << key_events[i].key_code << "\n" |
308 << "UnmodifiedText: " << key_events[i].unmodified_text << "\n" | 477 << "UnmodifiedText: " << key_events[i].unmodified_text << "\n" |
309 << "ModifiedText: " << key_events[i].modified_text << "\n" | 478 << "ModifiedText: " << key_events[i].modified_text << "\n" |
310 << "Modifiers: " << key_events[i].modifiers << "\n"; | 479 << "Modifiers: " << key_events[i].modifiers << "\n"; |
311 *success = false; | 480 *success = false; |
312 } | 481 } |
313 } | 482 } |
314 } | 483 } |
315 | 484 |
| 485 ErrorCode Session::SwitchToFrameWithJavaScriptLocatedFrame( |
| 486 const std::string& script, |
| 487 ListValue* args) { |
| 488 Value* unscoped_result = NULL; |
| 489 ErrorCode code = ExecuteScript(script, args, &unscoped_result); |
| 490 scoped_ptr<Value> result(unscoped_result); |
| 491 if (code != kSuccess) |
| 492 return code; |
| 493 std::string xpath; |
| 494 if (result->GetAsString(&xpath)) { |
| 495 if (current_frame_xpath_.length()) |
| 496 current_frame_xpath_ += "\n"; |
| 497 current_frame_xpath_ += xpath; |
| 498 return kSuccess; |
| 499 } |
| 500 return kNoSuchFrame; |
| 501 } |
| 502 |
316 } // namespace webdriver | 503 } // namespace webdriver |
OLD | NEW |