Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: chrome/test/chromedriver/commands.cc

Issue 19616008: [chromedriver] Allow commands to be async. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/test/chromedriver/commands.h ('k') | chrome/test/chromedriver/commands_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/lazy_instance.h"
9 #include "base/logging.h" // For CHECK macros. 13 #include "base/logging.h" // For CHECK macros.
14 #include "base/memory/linked_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/message_loop/message_loop_proxy.h"
17 #include "base/run_loop.h"
10 #include "base/strings/stringprintf.h" 18 #include "base/strings/stringprintf.h"
11 #include "base/sys_info.h" 19 #include "base/sys_info.h"
20 #include "base/threading/thread_local.h"
12 #include "base/values.h" 21 #include "base/values.h"
13 #include "chrome/test/chromedriver/capabilities.h" 22 #include "chrome/test/chromedriver/capabilities.h"
14 #include "chrome/test/chromedriver/chrome/chrome.h" 23 #include "chrome/test/chromedriver/chrome/chrome.h"
15 #include "chrome/test/chromedriver/chrome/chrome_android_impl.h" 24 #include "chrome/test/chromedriver/chrome/chrome_android_impl.h"
16 #include "chrome/test/chromedriver/chrome/chrome_desktop_impl.h" 25 #include "chrome/test/chromedriver/chrome/chrome_desktop_impl.h"
17 #include "chrome/test/chromedriver/chrome/device_manager.h" 26 #include "chrome/test/chromedriver/chrome/device_manager.h"
18 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h" 27 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
19 #include "chrome/test/chromedriver/chrome/status.h" 28 #include "chrome/test/chromedriver/chrome/status.h"
20 #include "chrome/test/chromedriver/chrome/version.h" 29 #include "chrome/test/chromedriver/chrome/version.h"
21 #include "chrome/test/chromedriver/chrome/web_view.h" 30 #include "chrome/test/chromedriver/chrome/web_view.h"
22 #include "chrome/test/chromedriver/chrome_launcher.h" 31 #include "chrome/test/chromedriver/chrome_launcher.h"
23 #include "chrome/test/chromedriver/logging.h" 32 #include "chrome/test/chromedriver/logging.h"
24 #include "chrome/test/chromedriver/net/net_util.h" 33 #include "chrome/test/chromedriver/net/net_util.h"
25 #include "chrome/test/chromedriver/net/url_request_context_getter.h" 34 #include "chrome/test/chromedriver/net/url_request_context_getter.h"
26 #include "chrome/test/chromedriver/session.h" 35 #include "chrome/test/chromedriver/session.h"
27 #include "chrome/test/chromedriver/session_map.h" 36 #include "chrome/test/chromedriver/session_thread_map.h"
28 #include "chrome/test/chromedriver/util.h" 37 #include "chrome/test/chromedriver/util.h"
29 38
30 Status ExecuteGetStatus( 39 void ExecuteGetStatus(
31 const base::DictionaryValue& params, 40 const base::DictionaryValue& params,
32 const std::string& session_id, 41 const std::string& session_id,
33 scoped_ptr<base::Value>* out_value, 42 const CommandCallback& callback) {
34 std::string* out_session_id) {
35 base::DictionaryValue build; 43 base::DictionaryValue build;
36 build.SetString("version", "alpha"); 44 build.SetString("version", "alpha");
37 45
38 base::DictionaryValue os; 46 base::DictionaryValue os;
39 os.SetString("name", base::SysInfo::OperatingSystemName()); 47 os.SetString("name", base::SysInfo::OperatingSystemName());
40 os.SetString("version", base::SysInfo::OperatingSystemVersion()); 48 os.SetString("version", base::SysInfo::OperatingSystemVersion());
41 os.SetString("arch", base::SysInfo::OperatingSystemArchitecture()); 49 os.SetString("arch", base::SysInfo::OperatingSystemArchitecture());
42 50
43 base::DictionaryValue info; 51 base::DictionaryValue info;
44 info.Set("build", build.DeepCopy()); 52 info.Set("build", build.DeepCopy());
45 info.Set("os", os.DeepCopy()); 53 info.Set("os", os.DeepCopy());
46 out_value->reset(info.DeepCopy()); 54 callback.Run(
47 return Status(kOk); 55 Status(kOk), scoped_ptr<base::Value>(info.DeepCopy()), std::string());
48 } 56 }
49 57
50 NewSessionParams::NewSessionParams( 58 NewSessionParams::NewSessionParams(
51 Log* log, 59 Log* log,
52 SessionMap* session_map, 60 SessionThreadMap* session_thread_map,
53 scoped_refptr<URLRequestContextGetter> context_getter, 61 scoped_refptr<URLRequestContextGetter> context_getter,
54 const SyncWebSocketFactory& socket_factory, 62 const SyncWebSocketFactory& socket_factory,
55 DeviceManager* device_manager) 63 DeviceManager* device_manager)
56 : log(log), 64 : log(log),
57 session_map(session_map), 65 session_thread_map(session_thread_map),
58 context_getter(context_getter), 66 context_getter(context_getter),
59 socket_factory(socket_factory), 67 socket_factory(socket_factory),
60 device_manager(device_manager) {} 68 device_manager(device_manager) {}
61 69
62 NewSessionParams::~NewSessionParams() {} 70 NewSessionParams::~NewSessionParams() {}
63 71
64 Status ExecuteNewSession( 72 namespace {
73
74 base::LazyInstance<base::ThreadLocalPointer<Session> >
75 lazy_tls_session = LAZY_INSTANCE_INITIALIZER;
76
77 Status CreateSessionOnSessionThreadHelper(
65 const NewSessionParams& bound_params, 78 const NewSessionParams& bound_params,
66 const base::DictionaryValue& params, 79 const base::DictionaryValue& params,
67 const std::string& session_id, 80 const std::string& session_id,
68 scoped_ptr<base::Value>* out_value, 81 scoped_ptr<base::Value>* out_value) {
69 std::string* out_session_id) {
70 int port; 82 int port;
71 if (!FindOpenPort(&port)) 83 if (!FindOpenPort(&port))
72 return Status(kUnknownError, "failed to find an open port for Chrome"); 84 return Status(kUnknownError, "failed to find an open port for Chrome");
73 85
74 const base::DictionaryValue* desired_caps; 86 const base::DictionaryValue* desired_caps;
75 if (!params.GetDictionary("desiredCapabilities", &desired_caps)) 87 if (!params.GetDictionary("desiredCapabilities", &desired_caps))
76 return Status(kUnknownError, "cannot find dict 'desiredCapabilities'"); 88 return Status(kUnknownError, "cannot find dict 'desiredCapabilities'");
77 89
78 Capabilities capabilities; 90 Capabilities capabilities;
79 Status status = capabilities.Parse(*desired_caps); 91 Status status = capabilities.Parse(*desired_caps);
(...skipping 21 matching lines...) Expand all
101 return status; 113 return status;
102 114
103 std::list<std::string> web_view_ids; 115 std::list<std::string> web_view_ids;
104 status = chrome->GetWebViewIds(&web_view_ids); 116 status = chrome->GetWebViewIds(&web_view_ids);
105 if (status.IsError() || web_view_ids.empty()) { 117 if (status.IsError() || web_view_ids.empty()) {
106 chrome->Quit(); 118 chrome->Quit();
107 return status.IsError() ? status : 119 return status.IsError() ? status :
108 Status(kUnknownError, "unable to discover open window in chrome"); 120 Status(kUnknownError, "unable to discover open window in chrome");
109 } 121 }
110 122
123 scoped_ptr<Session> session(new Session(session_id, chrome.Pass()));
124 session->devtools_logs.swap(devtools_logs);
125 session->window = web_view_ids.front();
126 session->detach = capabilities.detach;
127 out_value->reset(session->capabilities->DeepCopy());
128 lazy_tls_session.Pointer()->Set(session.release());
129 return Status(kOk);
130 }
131
132 void CreateSessionOnSessionThread(
133 const scoped_refptr<base::SingleThreadTaskRunner>& cmd_task_runner,
134 const NewSessionParams& bound_params,
135 scoped_ptr<base::DictionaryValue> params,
136 const std::string& session_id,
137 const CommandCallback& callback_on_cmd) {
138 scoped_ptr<base::Value> value;
139 Status status = CreateSessionOnSessionThreadHelper(
140 bound_params, *params, session_id, &value);
141 cmd_task_runner->PostTask(
142 FROM_HERE,
143 base::Bind(callback_on_cmd, status, base::Passed(&value), session_id));
144 }
145
146 } // namespace
147
148 void ExecuteNewSession(
149 const NewSessionParams& bound_params,
150 const base::DictionaryValue& params,
151 const std::string& session_id,
152 const CommandCallback& callback) {
111 std::string new_id = session_id; 153 std::string new_id = session_id;
112 if (new_id.empty()) 154 if (new_id.empty())
113 new_id = GenerateId(); 155 new_id = GenerateId();
114 scoped_ptr<Session> session(new Session(new_id, chrome.Pass())); 156 scoped_ptr<base::Thread> thread(new base::Thread(new_id.c_str()));
115 session->devtools_logs.swap(devtools_logs); 157 if (!thread->Start()) {
116 if (!session->thread.Start()) { 158 callback.Run(
117 chrome->Quit(); 159 Status(kUnknownError, "failed to start a thread for the new session"),
118 return Status(kUnknownError, 160 scoped_ptr<base::Value>(),
119 "failed to start a thread for the new session"); 161 std::string());
162 return;
120 } 163 }
121 session->window = web_view_ids.front();
122 session->detach = capabilities.detach;
123 out_value->reset(session->capabilities->DeepCopy());
124 *out_session_id = new_id;
125 164
126 scoped_refptr<SessionAccessor> accessor( 165 thread->message_loop()
127 new SessionAccessorImpl(session.Pass())); 166 ->PostTask(FROM_HERE,
128 bound_params.session_map->Set(new_id, accessor); 167 base::Bind(&CreateSessionOnSessionThread,
129 168 base::MessageLoopProxy::current(),
130 return Status(kOk); 169 bound_params,
170 base::Passed(make_scoped_ptr(params.DeepCopy())),
171 new_id,
172 callback));
173 bound_params.session_thread_map
174 ->insert(std::make_pair(new_id, make_linked_ptr(thread.release())));
131 } 175 }
132 176
133 Status ExecuteQuit( 177 namespace {
134 bool allow_detach, 178
135 SessionMap* session_map, 179 void OnSessionQuit(const base::WeakPtr<size_t>& quit_remaining_count,
180 const base::Closure& all_quit_func,
181 const Status& status,
182 scoped_ptr<base::Value> value,
183 const std::string& session_id) {
184 // |quit_remaining_count| may no longer be valid if a timeout occurred.
185 if (!quit_remaining_count)
186 return;
187
188 (*quit_remaining_count)--;
189 if (!*quit_remaining_count)
190 all_quit_func.Run();
191 }
192
193 } // namespace
194
195 void ExecuteQuitAll(
196 const Command& quit_command,
197 SessionThreadMap* session_thread_map,
136 const base::DictionaryValue& params, 198 const base::DictionaryValue& params,
137 const std::string& session_id, 199 const std::string& session_id,
138 scoped_ptr<base::Value>* out_value, 200 const CommandCallback& callback) {
139 std::string* out_session_id) { 201 size_t quit_remaining_count = session_thread_map->size();
140 *out_session_id = session_id; 202 base::WeakPtrFactory<size_t> weak_ptr_factory(&quit_remaining_count);
141 scoped_refptr<SessionAccessor> session_accessor; 203 if (!quit_remaining_count) {
142 if (!session_map->Get(session_id, &session_accessor)) 204 callback.Run(Status(kOk), scoped_ptr<base::Value>(), session_id);
143 return Status(kOk); 205 return;
144 scoped_ptr<base::AutoLock> session_lock; 206 }
145 Session* session = session_accessor->Access(&session_lock); 207 base::RunLoop run_loop;
146 if (!session) 208 for (SessionThreadMap::const_iterator iter = session_thread_map->begin();
147 return Status(kOk); 209 iter != session_thread_map->end();
148 CHECK(session_map->Remove(session->id)); 210 ++iter) {
149 if (allow_detach && session->detach) { 211 quit_command.Run(params,
150 session_accessor->DeleteSession(); 212 iter->first,
151 return Status(kOk); 213 base::Bind(&OnSessionQuit,
152 } else { 214 weak_ptr_factory.GetWeakPtr(),
153 Status status = session->chrome->Quit(); 215 run_loop.QuitClosure()));
154 session_accessor->DeleteSession(); 216 }
155 return status; 217 base::MessageLoop::current()->PostDelayedTask(
218 FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromSeconds(10));
219 // Uses a nested run loop to block this thread until all the quit
220 // commands have executed, or the timeout expires.
221 base::MessageLoop::current()->SetNestableTasksAllowed(true);
222 run_loop.Run();
223 callback.Run(Status(kOk), scoped_ptr<base::Value>(), session_id);
224 }
225
226 namespace {
227
228 void TerminateSessionThreadOnCommandThread(SessionThreadMap* session_thread_map,
229 const std::string& session_id) {
230 session_thread_map->erase(session_id);
231 }
232
233 void ExecuteSessionCommandOnSessionThread(
234 const SessionCommand& command,
235 bool return_ok_without_session,
236 scoped_ptr<base::DictionaryValue> params,
237 scoped_refptr<base::SingleThreadTaskRunner> cmd_task_runner,
238 const CommandCallback& callback_on_cmd,
239 const base::Closure& terminate_on_cmd) {
240 Session* session = lazy_tls_session.Pointer()->Get();
241 if (!session) {
242 cmd_task_runner->PostTask(
243 FROM_HERE,
244 base::Bind(callback_on_cmd,
245 Status(return_ok_without_session ? kOk : kNoSuchSession),
246 base::Passed(scoped_ptr<base::Value>()),
247 std::string()));
248 return;
249 }
250
251 scoped_ptr<base::Value> value;
252 Status status = command.Run(session, *params, &value);
253 if (status.IsError() && session->chrome)
254 status.AddDetails("Session info: chrome=" + session->chrome->GetVersion());
255
256 cmd_task_runner->PostTask(
257 FROM_HERE,
258 base::Bind(callback_on_cmd, status, base::Passed(&value), session->id));
259
260 if (session->quit) {
261 lazy_tls_session.Pointer()->Set(NULL);
262 delete session;
263 cmd_task_runner->PostTask(FROM_HERE, terminate_on_cmd);
156 } 264 }
157 } 265 }
158 266
159 Status ExecuteQuitAll( 267 } // namespace
160 Command quit_command, 268
161 SessionMap* session_map, 269 void ExecuteSessionCommand(
270 SessionThreadMap* session_thread_map,
271 const SessionCommand& command,
272 bool return_ok_without_session,
162 const base::DictionaryValue& params, 273 const base::DictionaryValue& params,
163 const std::string& session_id, 274 const std::string& session_id,
164 scoped_ptr<base::Value>* out_value, 275 const CommandCallback& callback) {
165 std::string* out_session_id) { 276 SessionThreadMap::iterator iter = session_thread_map->find(session_id);
166 std::vector<std::string> session_ids; 277 if (iter == session_thread_map->end()) {
167 session_map->GetKeys(&session_ids); 278 Status status(return_ok_without_session ? kOk : kNoSuchSession);
168 for (size_t i = 0; i < session_ids.size(); ++i) { 279 callback.Run(status, scoped_ptr<base::Value>(), session_id);
169 scoped_ptr<base::Value> unused_value; 280 } else {
170 std::string unused_session_id; 281 iter->second->message_loop()
171 quit_command.Run(params, session_ids[i], &unused_value, &unused_session_id); 282 ->PostTask(FROM_HERE,
283 base::Bind(&ExecuteSessionCommandOnSessionThread,
284 command,
285 return_ok_without_session,
286 base::Passed(make_scoped_ptr(params.DeepCopy())),
287 base::MessageLoopProxy::current(),
288 callback,
289 base::Bind(&TerminateSessionThreadOnCommandThread,
290 session_thread_map,
291 session_id)));
172 } 292 }
173 return Status(kOk);
174 } 293 }
294
295 namespace internal {
296
297 void CreateSessionOnSessionThreadForTesting(const std::string& id) {
298 lazy_tls_session.Pointer()->Set(new Session(id));
299 }
300
301 } // namespace internal
OLDNEW
« no previous file with comments | « chrome/test/chromedriver/commands.h ('k') | chrome/test/chromedriver/commands_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698