Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / test / chromedriver / commands.cc
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
3 // found in the LICENSE file.
4
5 #include "chrome/test/chromedriver/commands.h"
6
7 #include <algorithm>
8 #include <list>
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/logging.h"
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"
18 #include "base/strings/stringprintf.h"
19 #include "base/sys_info.h"
20 #include "base/values.h"
21 #include "chrome/test/chromedriver/capabilities.h"
22 #include "chrome/test/chromedriver/chrome/chrome.h"
23 #include "chrome/test/chromedriver/chrome/status.h"
24 #include "chrome/test/chromedriver/chrome/version.h"
25 #include "chrome/test/chromedriver/logging.h"
26 #include "chrome/test/chromedriver/session.h"
27 #include "chrome/test/chromedriver/session_thread_map.h"
28 #include "chrome/test/chromedriver/util.h"
29
30 void ExecuteGetStatus(
31     const base::DictionaryValue& params,
32     const std::string& session_id,
33     const CommandCallback& callback) {
34   base::DictionaryValue build;
35   build.SetString("version", "alpha");
36
37   base::DictionaryValue os;
38   os.SetString("name", base::SysInfo::OperatingSystemName());
39   os.SetString("version", base::SysInfo::OperatingSystemVersion());
40   os.SetString("arch", base::SysInfo::OperatingSystemArchitecture());
41
42   base::DictionaryValue info;
43   info.Set("build", build.DeepCopy());
44   info.Set("os", os.DeepCopy());
45   callback.Run(
46       Status(kOk), scoped_ptr<base::Value>(info.DeepCopy()), std::string());
47 }
48
49 void ExecuteCreateSession(
50     SessionThreadMap* session_thread_map,
51     const Command& init_session_cmd,
52     const base::DictionaryValue& params,
53     const std::string& session_id,
54     const CommandCallback& callback) {
55   std::string new_id = session_id;
56   if (new_id.empty())
57     new_id = GenerateId();
58   scoped_ptr<Session> session(new Session(new_id));
59   scoped_ptr<base::Thread> thread(new base::Thread(new_id));
60   if (!thread->Start()) {
61     callback.Run(
62         Status(kUnknownError, "failed to start a thread for the new session"),
63         scoped_ptr<base::Value>(),
64         std::string());
65     return;
66   }
67
68   thread->message_loop()->PostTask(
69       FROM_HERE, base::Bind(&SetThreadLocalSession, base::Passed(&session)));
70   session_thread_map
71       ->insert(std::make_pair(new_id, make_linked_ptr(thread.release())));
72   init_session_cmd.Run(params, new_id, callback);
73 }
74
75 namespace {
76
77 void OnSessionQuit(const base::WeakPtr<size_t>& quit_remaining_count,
78                    const base::Closure& all_quit_func,
79                    const Status& status,
80                    scoped_ptr<base::Value> value,
81                    const std::string& session_id) {
82   // |quit_remaining_count| may no longer be valid if a timeout occurred.
83   if (!quit_remaining_count)
84     return;
85
86   (*quit_remaining_count)--;
87   if (!*quit_remaining_count)
88     all_quit_func.Run();
89 }
90
91 }  // namespace
92
93 void ExecuteQuitAll(
94     const Command& quit_command,
95     SessionThreadMap* session_thread_map,
96     const base::DictionaryValue& params,
97     const std::string& session_id,
98     const CommandCallback& callback) {
99   size_t quit_remaining_count = session_thread_map->size();
100   base::WeakPtrFactory<size_t> weak_ptr_factory(&quit_remaining_count);
101   if (!quit_remaining_count) {
102     callback.Run(Status(kOk), scoped_ptr<base::Value>(), session_id);
103     return;
104   }
105   base::RunLoop run_loop;
106   for (SessionThreadMap::const_iterator iter = session_thread_map->begin();
107        iter != session_thread_map->end();
108        ++iter) {
109     quit_command.Run(params,
110                      iter->first,
111                      base::Bind(&OnSessionQuit,
112                                 weak_ptr_factory.GetWeakPtr(),
113                                 run_loop.QuitClosure()));
114   }
115   base::MessageLoop::current()->PostDelayedTask(
116       FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromSeconds(10));
117   // Uses a nested run loop to block this thread until all the quit
118   // commands have executed, or the timeout expires.
119   base::MessageLoop::current()->SetNestableTasksAllowed(true);
120   run_loop.Run();
121   callback.Run(Status(kOk), scoped_ptr<base::Value>(), session_id);
122 }
123
124 namespace {
125
126 void TerminateSessionThreadOnCommandThread(SessionThreadMap* session_thread_map,
127                                            const std::string& session_id) {
128   session_thread_map->erase(session_id);
129 }
130
131 void ExecuteSessionCommandOnSessionThread(
132     const char* command_name,
133     const SessionCommand& command,
134     bool return_ok_without_session,
135     scoped_ptr<base::DictionaryValue> params,
136     scoped_refptr<base::SingleThreadTaskRunner> cmd_task_runner,
137     const CommandCallback& callback_on_cmd,
138     const base::Closure& terminate_on_cmd) {
139   Session* session = GetThreadLocalSession();
140   if (!session) {
141     cmd_task_runner->PostTask(
142         FROM_HERE,
143         base::Bind(callback_on_cmd,
144                    Status(return_ok_without_session ? kOk : kNoSuchSession),
145                    base::Passed(scoped_ptr<base::Value>()),
146                    std::string()));
147     return;
148   }
149
150   if (IsVLogOn(0)) {
151     VLOG(0) << "COMMAND " << command_name << " "
152             << FormatValueForDisplay(*params);
153   }
154   scoped_ptr<base::Value> value;
155   Status status = command.Run(session, *params, &value);
156
157   if (status.IsError() && session->chrome) {
158     if (!session->quit && session->chrome->HasCrashedWebView()) {
159       session->quit = true;
160       std::string message("session deleted because of page crash");
161       if (!session->detach) {
162         Status quit_status = session->chrome->Quit();
163         if (quit_status.IsError())
164           message += ", but failed to kill browser:" + quit_status.message();
165       }
166       status = Status(kUnknownError, message, status);
167     } else if (status.code() == kDisconnected) {
168       // Some commands, like clicking a button or link which closes the window,
169       // may result in a kDisconnected error code.
170       std::list<std::string> web_view_ids;
171       Status status_tmp = session->chrome->GetWebViewIds(&web_view_ids);
172       if (status_tmp.IsError() && status_tmp.code() != kChromeNotReachable) {
173         status.AddDetails(
174             "failed to check if window was closed: " + status_tmp.message());
175       } else if (std::find(web_view_ids.begin(),
176                            web_view_ids.end(),
177                            session->window) == web_view_ids.end()) {
178         status = Status(kOk);
179       }
180     }
181     if (status.IsError()) {
182       const BrowserInfo* browser_info = session->chrome->GetBrowserInfo();
183       status.AddDetails("Session info: " + browser_info->browser_name + "=" +
184                         browser_info->browser_version);
185     }
186   }
187
188   if (IsVLogOn(0)) {
189     std::string result;
190     if (status.IsError()) {
191       result = status.message();
192     } else if (value) {
193       result = FormatValueForDisplay(*value);
194     }
195     VLOG(0) << "RESPONSE " << command_name
196             << (result.length() ? " " + result : "");
197   }
198
199   if (status.IsOk() && session->auto_reporting_enabled) {
200     std::string message = session->GetFirstBrowserError();
201     if (!message.empty())
202       status = Status(kUnknownError, message);
203   }
204
205   cmd_task_runner->PostTask(
206       FROM_HERE,
207       base::Bind(callback_on_cmd, status, base::Passed(&value), session->id));
208
209   if (session->quit) {
210     SetThreadLocalSession(scoped_ptr<Session>());
211     delete session;
212     cmd_task_runner->PostTask(FROM_HERE, terminate_on_cmd);
213   }
214 }
215
216 }  // namespace
217
218 void ExecuteSessionCommand(
219     SessionThreadMap* session_thread_map,
220     const char* command_name,
221     const SessionCommand& command,
222     bool return_ok_without_session,
223     const base::DictionaryValue& params,
224     const std::string& session_id,
225     const CommandCallback& callback) {
226   SessionThreadMap::iterator iter = session_thread_map->find(session_id);
227   if (iter == session_thread_map->end()) {
228     Status status(return_ok_without_session ? kOk : kNoSuchSession);
229     callback.Run(status, scoped_ptr<base::Value>(), session_id);
230   } else {
231     iter->second->message_loop()
232         ->PostTask(FROM_HERE,
233                    base::Bind(&ExecuteSessionCommandOnSessionThread,
234                               command_name,
235                               command,
236                               return_ok_without_session,
237                               base::Passed(make_scoped_ptr(params.DeepCopy())),
238                               base::MessageLoopProxy::current(),
239                               callback,
240                               base::Bind(&TerminateSessionThreadOnCommandThread,
241                                          session_thread_map,
242                                          session_id)));
243   }
244 }
245
246 namespace internal {
247
248 void CreateSessionOnSessionThreadForTesting(const std::string& id) {
249   SetThreadLocalSession(make_scoped_ptr(new Session(id)));
250 }
251
252 }  // namespace internal