Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/chromedriver/commands.h" | 5 #include "chrome/test/chromedriver/commands.h" |
| 6 | 6 |
| 7 #include <list> | 7 #include <list> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
| 12 #include "base/lazy_instance.h" | |
| 13 #include "base/logging.h" // For CHECK macros. | 12 #include "base/logging.h" // For CHECK macros. |
| 14 #include "base/memory/linked_ptr.h" | 13 #include "base/memory/linked_ptr.h" |
| 15 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
| 16 #include "base/message_loop/message_loop_proxy.h" | 15 #include "base/message_loop/message_loop_proxy.h" |
| 17 #include "base/run_loop.h" | 16 #include "base/run_loop.h" |
| 18 #include "base/strings/stringprintf.h" | 17 #include "base/strings/stringprintf.h" |
| 19 #include "base/sys_info.h" | 18 #include "base/sys_info.h" |
| 20 #include "base/threading/thread_local.h" | |
| 21 #include "base/values.h" | 19 #include "base/values.h" |
| 22 #include "chrome/test/chromedriver/capabilities.h" | 20 #include "chrome/test/chromedriver/capabilities.h" |
| 23 #include "chrome/test/chromedriver/chrome/chrome.h" | 21 #include "chrome/test/chromedriver/chrome/chrome.h" |
| 24 #include "chrome/test/chromedriver/chrome/chrome_android_impl.h" | |
| 25 #include "chrome/test/chromedriver/chrome/chrome_desktop_impl.h" | |
| 26 #include "chrome/test/chromedriver/chrome/device_manager.h" | |
| 27 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h" | |
| 28 #include "chrome/test/chromedriver/chrome/status.h" | 22 #include "chrome/test/chromedriver/chrome/status.h" |
| 29 #include "chrome/test/chromedriver/chrome/version.h" | |
| 30 #include "chrome/test/chromedriver/chrome/web_view.h" | |
| 31 #include "chrome/test/chromedriver/chrome_launcher.h" | |
| 32 #include "chrome/test/chromedriver/logging.h" | 23 #include "chrome/test/chromedriver/logging.h" |
| 33 #include "chrome/test/chromedriver/net/net_util.h" | |
| 34 #include "chrome/test/chromedriver/net/url_request_context_getter.h" | |
| 35 #include "chrome/test/chromedriver/session.h" | 24 #include "chrome/test/chromedriver/session.h" |
| 36 #include "chrome/test/chromedriver/session_thread_map.h" | 25 #include "chrome/test/chromedriver/session_thread_map.h" |
| 37 #include "chrome/test/chromedriver/util.h" | 26 #include "chrome/test/chromedriver/util.h" |
| 38 | 27 |
| 39 void ExecuteGetStatus( | 28 void ExecuteGetStatus( |
| 40 const base::DictionaryValue& params, | 29 const base::DictionaryValue& params, |
| 41 const std::string& session_id, | 30 const std::string& session_id, |
| 42 const CommandCallback& callback) { | 31 const CommandCallback& callback) { |
| 43 base::DictionaryValue build; | 32 base::DictionaryValue build; |
| 44 build.SetString("version", "alpha"); | 33 build.SetString("version", "alpha"); |
| 45 | 34 |
| 46 base::DictionaryValue os; | 35 base::DictionaryValue os; |
| 47 os.SetString("name", base::SysInfo::OperatingSystemName()); | 36 os.SetString("name", base::SysInfo::OperatingSystemName()); |
| 48 os.SetString("version", base::SysInfo::OperatingSystemVersion()); | 37 os.SetString("version", base::SysInfo::OperatingSystemVersion()); |
| 49 os.SetString("arch", base::SysInfo::OperatingSystemArchitecture()); | 38 os.SetString("arch", base::SysInfo::OperatingSystemArchitecture()); |
| 50 | 39 |
| 51 base::DictionaryValue info; | 40 base::DictionaryValue info; |
| 52 info.Set("build", build.DeepCopy()); | 41 info.Set("build", build.DeepCopy()); |
| 53 info.Set("os", os.DeepCopy()); | 42 info.Set("os", os.DeepCopy()); |
| 54 callback.Run( | 43 callback.Run( |
| 55 Status(kOk), scoped_ptr<base::Value>(info.DeepCopy()), std::string()); | 44 Status(kOk), scoped_ptr<base::Value>(info.DeepCopy()), std::string()); |
| 56 } | 45 } |
| 57 | 46 |
| 58 NewSessionParams::NewSessionParams( | 47 void ExecuteCreateSession( |
| 59 SessionThreadMap* session_thread_map, | 48 SessionThreadMap* session_thread_map, |
| 60 scoped_refptr<URLRequestContextGetter> context_getter, | 49 const Command& init_session_cmd, |
| 61 const SyncWebSocketFactory& socket_factory, | |
| 62 DeviceManager* device_manager) | |
| 63 : session_thread_map(session_thread_map), | |
| 64 context_getter(context_getter), | |
| 65 socket_factory(socket_factory), | |
| 66 device_manager(device_manager) {} | |
| 67 | |
| 68 NewSessionParams::~NewSessionParams() {} | |
| 69 | |
| 70 namespace { | |
| 71 | |
| 72 base::LazyInstance<base::ThreadLocalPointer<Session> > | |
| 73 lazy_tls_session = LAZY_INSTANCE_INITIALIZER; | |
| 74 | |
| 75 Status CreateSessionOnSessionThreadHelper( | |
| 76 const NewSessionParams& bound_params, | |
| 77 const base::DictionaryValue& params, | |
| 78 const std::string& session_id, | |
| 79 scoped_ptr<base::Value>* out_value) { | |
| 80 const base::DictionaryValue* desired_caps; | |
| 81 if (!params.GetDictionary("desiredCapabilities", &desired_caps)) | |
| 82 return Status(kUnknownError, "cannot find dict 'desiredCapabilities'"); | |
| 83 | |
| 84 Capabilities capabilities; | |
| 85 Status status = capabilities.Parse(*desired_caps); | |
| 86 if (status.IsError()) | |
| 87 return status; | |
| 88 | |
| 89 // Create Log's and DevToolsEventListener's for ones that are DevTools-based. | |
| 90 // Session will own the Log's, Chrome will own the listeners. | |
| 91 ScopedVector<WebDriverLog> devtools_logs; | |
| 92 // TODO(kkania): Save this log in the session. | |
| 93 scoped_ptr<WebDriverLog> driver_log; | |
| 94 ScopedVector<DevToolsEventListener> devtools_event_listeners; | |
| 95 status = CreateLogs( | |
| 96 capabilities, &devtools_logs, &driver_log, &devtools_event_listeners); | |
| 97 if (status.IsError()) | |
| 98 return status; | |
| 99 | |
| 100 scoped_ptr<Chrome> chrome; | |
| 101 status = LaunchChrome(bound_params.context_getter.get(), | |
| 102 bound_params.socket_factory, | |
| 103 bound_params.device_manager, | |
| 104 capabilities, | |
| 105 devtools_event_listeners, | |
| 106 &chrome); | |
| 107 if (status.IsError()) | |
| 108 return status; | |
| 109 | |
| 110 std::list<std::string> web_view_ids; | |
| 111 status = chrome->GetWebViewIds(&web_view_ids); | |
| 112 if (status.IsError() || web_view_ids.empty()) { | |
| 113 chrome->Quit(); | |
| 114 return status.IsError() ? status : | |
| 115 Status(kUnknownError, "unable to discover open window in chrome"); | |
| 116 } | |
| 117 | |
| 118 scoped_ptr<Session> session(new Session(session_id, chrome.Pass())); | |
| 119 session->devtools_logs.swap(devtools_logs); | |
| 120 session->window = web_view_ids.front(); | |
| 121 session->detach = capabilities.detach; | |
| 122 session->force_devtools_screenshot = capabilities.force_devtools_screenshot; | |
| 123 out_value->reset(session->capabilities->DeepCopy()); | |
| 124 lazy_tls_session.Pointer()->Set(session.release()); | |
| 125 return Status(kOk); | |
| 126 } | |
| 127 | |
| 128 void CreateSessionOnSessionThread( | |
| 129 const scoped_refptr<base::SingleThreadTaskRunner>& cmd_task_runner, | |
| 130 const NewSessionParams& bound_params, | |
| 131 scoped_ptr<base::DictionaryValue> params, | |
| 132 const std::string& session_id, | |
| 133 const CommandCallback& callback_on_cmd) { | |
| 134 scoped_ptr<base::Value> value; | |
| 135 Status status = CreateSessionOnSessionThreadHelper( | |
| 136 bound_params, *params, session_id, &value); | |
| 137 cmd_task_runner->PostTask( | |
| 138 FROM_HERE, | |
| 139 base::Bind(callback_on_cmd, status, base::Passed(&value), session_id)); | |
| 140 } | |
| 141 | |
| 142 } // namespace | |
| 143 | |
| 144 void ExecuteNewSession( | |
| 145 const NewSessionParams& bound_params, | |
| 146 const base::DictionaryValue& params, | 50 const base::DictionaryValue& params, |
| 147 const std::string& session_id, | 51 const std::string& session_id, |
| 148 const CommandCallback& callback) { | 52 const CommandCallback& callback) { |
| 149 std::string new_id = session_id; | 53 std::string new_id = session_id; |
| 150 if (new_id.empty()) | 54 if (new_id.empty()) |
| 151 new_id = GenerateId(); | 55 new_id = GenerateId(); |
| 56 scoped_ptr<Session> session(new Session(new_id)); | |
| 152 scoped_ptr<base::Thread> thread(new base::Thread(new_id.c_str())); | 57 scoped_ptr<base::Thread> thread(new base::Thread(new_id.c_str())); |
| 153 if (!thread->Start()) { | 58 if (!thread->Start()) { |
| 154 callback.Run( | 59 callback.Run( |
| 155 Status(kUnknownError, "failed to start a thread for the new session"), | 60 Status(kUnknownError, "failed to start a thread for the new session"), |
| 156 scoped_ptr<base::Value>(), | 61 scoped_ptr<base::Value>(), |
| 157 std::string()); | 62 std::string()); |
| 158 return; | 63 return; |
| 159 } | 64 } |
| 160 | 65 |
| 161 thread->message_loop() | 66 thread->message_loop()->PostTask( |
| 162 ->PostTask(FROM_HERE, | 67 FROM_HERE, base::Bind(&SetThreadLocalSession, base::Passed(&session))); |
| 163 base::Bind(&CreateSessionOnSessionThread, | 68 session_thread_map |
| 164 base::MessageLoopProxy::current(), | |
| 165 bound_params, | |
| 166 base::Passed(make_scoped_ptr(params.DeepCopy())), | |
| 167 new_id, | |
| 168 callback)); | |
| 169 bound_params.session_thread_map | |
| 170 ->insert(std::make_pair(new_id, make_linked_ptr(thread.release()))); | 69 ->insert(std::make_pair(new_id, make_linked_ptr(thread.release()))); |
| 70 init_session_cmd.Run(params, new_id, callback); | |
|
chrisgao (Use stgao instead)
2013/09/06 21:20:13
I like this change, although it is a little hard f
kkania
2013/09/06 23:09:29
Done.
| |
| 171 } | 71 } |
| 172 | 72 |
| 173 namespace { | 73 namespace { |
| 174 | 74 |
| 175 void OnSessionQuit(const base::WeakPtr<size_t>& quit_remaining_count, | 75 void OnSessionQuit(const base::WeakPtr<size_t>& quit_remaining_count, |
| 176 const base::Closure& all_quit_func, | 76 const base::Closure& all_quit_func, |
| 177 const Status& status, | 77 const Status& status, |
| 178 scoped_ptr<base::Value> value, | 78 scoped_ptr<base::Value> value, |
| 179 const std::string& session_id) { | 79 const std::string& session_id) { |
| 180 // |quit_remaining_count| may no longer be valid if a timeout occurred. | 80 // |quit_remaining_count| may no longer be valid if a timeout occurred. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 220 } | 120 } |
| 221 | 121 |
| 222 namespace { | 122 namespace { |
| 223 | 123 |
| 224 void TerminateSessionThreadOnCommandThread(SessionThreadMap* session_thread_map, | 124 void TerminateSessionThreadOnCommandThread(SessionThreadMap* session_thread_map, |
| 225 const std::string& session_id) { | 125 const std::string& session_id) { |
| 226 session_thread_map->erase(session_id); | 126 session_thread_map->erase(session_id); |
| 227 } | 127 } |
| 228 | 128 |
| 229 void ExecuteSessionCommandOnSessionThread( | 129 void ExecuteSessionCommandOnSessionThread( |
| 130 const char* command_name, | |
| 230 const SessionCommand& command, | 131 const SessionCommand& command, |
| 231 bool return_ok_without_session, | 132 bool return_ok_without_session, |
| 232 scoped_ptr<base::DictionaryValue> params, | 133 scoped_ptr<base::DictionaryValue> params, |
| 233 scoped_refptr<base::SingleThreadTaskRunner> cmd_task_runner, | 134 scoped_refptr<base::SingleThreadTaskRunner> cmd_task_runner, |
| 234 const CommandCallback& callback_on_cmd, | 135 const CommandCallback& callback_on_cmd, |
| 235 const base::Closure& terminate_on_cmd) { | 136 const base::Closure& terminate_on_cmd) { |
| 236 Session* session = lazy_tls_session.Pointer()->Get(); | 137 Session* session = GetThreadLocalSession(); |
| 237 if (!session) { | 138 if (!session) { |
| 238 cmd_task_runner->PostTask( | 139 cmd_task_runner->PostTask( |
| 239 FROM_HERE, | 140 FROM_HERE, |
| 240 base::Bind(callback_on_cmd, | 141 base::Bind(callback_on_cmd, |
| 241 Status(return_ok_without_session ? kOk : kNoSuchSession), | 142 Status(return_ok_without_session ? kOk : kNoSuchSession), |
| 242 base::Passed(scoped_ptr<base::Value>()), | 143 base::Passed(scoped_ptr<base::Value>()), |
| 243 std::string())); | 144 std::string())); |
| 244 return; | 145 return; |
| 245 } | 146 } |
| 246 | 147 |
| 148 VLOG(0) << "COMMAND " << command_name << " " | |
|
chrisgao (Use stgao instead)
2013/09/06 21:20:13
I like command names than guessing from urls :)
Th
kkania
2013/09/06 23:09:29
Done.
| |
| 149 << PrettyPrintValue(*params); | |
|
chrisgao (Use stgao instead)
2013/09/06 21:20:13
No need to check if log is enabled?
kkania
2013/09/06 23:09:29
Done.
| |
| 247 scoped_ptr<base::Value> value; | 150 scoped_ptr<base::Value> value; |
| 248 Status status = command.Run(session, *params, &value); | 151 Status status = command.Run(session, *params, &value); |
| 249 if (status.IsError() && session->chrome) | 152 if (status.IsError() && session->chrome) |
| 250 status.AddDetails("Session info: chrome=" + session->chrome->GetVersion()); | 153 status.AddDetails("Session info: chrome=" + session->chrome->GetVersion()); |
| 251 | 154 |
| 155 if (IsVLogOn(0)) { | |
| 156 std::string result; | |
| 157 if (status.IsError()) { | |
| 158 result = status.message(); | |
| 159 } else if (value) { | |
| 160 result = FormatValueForDisplay(*value); | |
| 161 } | |
| 162 VLOG(0) << "RESPONSE " << command_name | |
| 163 << (result.length() ? " " + result : ""); | |
| 164 } | |
| 165 | |
| 252 cmd_task_runner->PostTask( | 166 cmd_task_runner->PostTask( |
| 253 FROM_HERE, | 167 FROM_HERE, |
| 254 base::Bind(callback_on_cmd, status, base::Passed(&value), session->id)); | 168 base::Bind(callback_on_cmd, status, base::Passed(&value), session->id)); |
| 255 | 169 |
| 256 if (session->quit) { | 170 if (session->quit) { |
| 257 lazy_tls_session.Pointer()->Set(NULL); | 171 SetThreadLocalSession(scoped_ptr<Session>()); |
| 258 delete session; | 172 delete session; |
| 259 cmd_task_runner->PostTask(FROM_HERE, terminate_on_cmd); | 173 cmd_task_runner->PostTask(FROM_HERE, terminate_on_cmd); |
| 260 } | 174 } |
| 261 } | 175 } |
| 262 | 176 |
| 263 } // namespace | 177 } // namespace |
| 264 | 178 |
| 265 void ExecuteSessionCommand( | 179 void ExecuteSessionCommand( |
| 266 SessionThreadMap* session_thread_map, | 180 SessionThreadMap* session_thread_map, |
| 181 const char* command_name, | |
| 267 const SessionCommand& command, | 182 const SessionCommand& command, |
| 268 bool return_ok_without_session, | 183 bool return_ok_without_session, |
| 269 const base::DictionaryValue& params, | 184 const base::DictionaryValue& params, |
| 270 const std::string& session_id, | 185 const std::string& session_id, |
| 271 const CommandCallback& callback) { | 186 const CommandCallback& callback) { |
| 272 SessionThreadMap::iterator iter = session_thread_map->find(session_id); | 187 SessionThreadMap::iterator iter = session_thread_map->find(session_id); |
| 273 if (iter == session_thread_map->end()) { | 188 if (iter == session_thread_map->end()) { |
| 274 Status status(return_ok_without_session ? kOk : kNoSuchSession); | 189 Status status(return_ok_without_session ? kOk : kNoSuchSession); |
| 275 callback.Run(status, scoped_ptr<base::Value>(), session_id); | 190 callback.Run(status, scoped_ptr<base::Value>(), session_id); |
| 276 } else { | 191 } else { |
| 277 iter->second->message_loop() | 192 iter->second->message_loop() |
| 278 ->PostTask(FROM_HERE, | 193 ->PostTask(FROM_HERE, |
| 279 base::Bind(&ExecuteSessionCommandOnSessionThread, | 194 base::Bind(&ExecuteSessionCommandOnSessionThread, |
| 195 command_name, | |
| 280 command, | 196 command, |
| 281 return_ok_without_session, | 197 return_ok_without_session, |
| 282 base::Passed(make_scoped_ptr(params.DeepCopy())), | 198 base::Passed(make_scoped_ptr(params.DeepCopy())), |
| 283 base::MessageLoopProxy::current(), | 199 base::MessageLoopProxy::current(), |
| 284 callback, | 200 callback, |
| 285 base::Bind(&TerminateSessionThreadOnCommandThread, | 201 base::Bind(&TerminateSessionThreadOnCommandThread, |
| 286 session_thread_map, | 202 session_thread_map, |
| 287 session_id))); | 203 session_id))); |
| 288 } | 204 } |
| 289 } | 205 } |
| 290 | 206 |
| 291 namespace internal { | 207 namespace internal { |
| 292 | 208 |
| 293 void CreateSessionOnSessionThreadForTesting(const std::string& id) { | 209 void CreateSessionOnSessionThreadForTesting(const std::string& id) { |
| 294 lazy_tls_session.Pointer()->Set(new Session(id)); | 210 SetThreadLocalSession(make_scoped_ptr(new Session(id))); |
| 295 } | 211 } |
| 296 | 212 |
| 297 } // namespace internal | 213 } // namespace internal |
| OLD | NEW |