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