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

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

Issue 12848005: [chromedriver] Separate stuff of chrome from chromedriver. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments and fix compile error on mac. Created 7 years, 9 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
OLDNEW
(Empty)
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/devtools_client_impl.h"
6
7 #include "base/bind.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/logging.h"
11 #include "base/values.h"
12 #include "chrome/test/chromedriver/devtools_event_listener.h"
13 #include "chrome/test/chromedriver/net/sync_websocket.h"
14 #include "chrome/test/chromedriver/net/url_request_context_getter.h"
15 #include "chrome/test/chromedriver/status.h"
16
17 namespace {
18
19 const char* kInspectorContextError =
20 "Execution context with given id not found.";
21
22 Status ParseInspectorError(const std::string& error_json) {
23 scoped_ptr<base::Value> error(base::JSONReader::Read(error_json));
24 base::DictionaryValue* error_dict;
25 if (!error || !error->GetAsDictionary(&error_dict))
26 return Status(kUnknownError, "inspector error with no error message");
27 std::string error_message;
28 if (error_dict->GetString("message", &error_message) &&
29 error_message == kInspectorContextError) {
30 return Status(kNoSuchFrame);
31 }
32 return Status(kUnknownError, "unhandled inspector error: " + error_json);
33 }
34
35 } // namespace
36
37 namespace internal {
38
39 InspectorEvent::InspectorEvent() {}
40
41 InspectorEvent::~InspectorEvent() {}
42
43 InspectorCommandResponse::InspectorCommandResponse() {}
44
45 InspectorCommandResponse::~InspectorCommandResponse() {}
46
47 } // namespace internal
48
49 DevToolsClientImpl::DevToolsClientImpl(
50 const SyncWebSocketFactory& factory,
51 const std::string& url,
52 const FrontendCloserFunc& frontend_closer_func)
53 : socket_(factory.Run().Pass()),
54 url_(url),
55 frontend_closer_func_(frontend_closer_func),
56 parser_func_(base::Bind(&internal::ParseInspectorMessage)),
57 next_id_(1) {}
58
59 DevToolsClientImpl::DevToolsClientImpl(
60 const SyncWebSocketFactory& factory,
61 const std::string& url,
62 const FrontendCloserFunc& frontend_closer_func,
63 const ParserFunc& parser_func)
64 : socket_(factory.Run().Pass()),
65 url_(url),
66 frontend_closer_func_(frontend_closer_func),
67 parser_func_(parser_func),
68 next_id_(1) {}
69
70 DevToolsClientImpl::~DevToolsClientImpl() {
71 for (ResponseMap::iterator iter = cmd_response_map_.begin();
72 iter != cmd_response_map_.end(); ++iter) {
73 LOG(WARNING) << "Finished with no response for command " << iter->first;
74 delete iter->second;
75 }
76 }
77
78 void DevToolsClientImpl::SetParserFuncForTesting(
79 const ParserFunc& parser_func) {
80 parser_func_ = parser_func;
81 }
82
83 Status DevToolsClientImpl::ConnectIfNecessary() {
84 if (!socket_->IsConnected()) {
85 if (!socket_->Connect(url_)) {
86 // Try to close devtools frontend and then reconnect.
87 Status status = frontend_closer_func_.Run();
88 if (status.IsError())
89 return status;
90 if (!socket_->Connect(url_))
91 return Status(kDisconnected, "unable to connect to renderer");
92 }
93
94 // OnConnected notification will be sent out in method ReceiveNextMessage.
95 listeners_for_on_connected_ = listeners_;
96 }
97 return Status(kOk);
98 }
99
100 Status DevToolsClientImpl::SendCommand(
101 const std::string& method,
102 const base::DictionaryValue& params) {
103 scoped_ptr<base::DictionaryValue> result;
104 return SendCommandInternal(method, params, &result);
105 }
106
107 Status DevToolsClientImpl::SendCommandAndGetResult(
108 const std::string& method,
109 const base::DictionaryValue& params,
110 scoped_ptr<base::DictionaryValue>* result) {
111 scoped_ptr<base::DictionaryValue> intermediate_result;
112 Status status = SendCommandInternal(method, params, &intermediate_result);
113 if (status.IsError())
114 return status;
115 if (!intermediate_result)
116 return Status(kUnknownError, "inspector response missing result");
117 result->reset(intermediate_result.release());
118 return Status(kOk);
119 }
120
121 void DevToolsClientImpl::AddListener(DevToolsEventListener* listener) {
122 DCHECK(listener);
123 listeners_.push_back(listener);
124 }
125
126 Status DevToolsClientImpl::HandleEventsUntil(
127 const ConditionalFunc& conditional_func) {
128 if (!socket_->IsConnected())
129 return Status(kDisconnected, "not connected to DevTools");
130
131 Status status = EnsureAllListenersNotifiedOfConnection();
132 if (status.IsError())
133 return status;
134
135 internal::InspectorMessageType type;
136 internal::InspectorEvent event;
137 internal::InspectorCommandResponse response;
138
139 while (true) {
140 if (!socket_->HasNextMessage()) {
141 bool is_condition_met;
142 Status status = conditional_func.Run(&is_condition_met);
143 if (status.IsError())
144 return status;
145 if (is_condition_met)
146 return Status(kOk);
147 }
148
149 status = ReceiveNextMessage(-1, &type, &event, &response);
150 if (status.IsError())
151 return status;
152 }
153 return Status(kOk);
154 }
155
156 Status DevToolsClientImpl::SendCommandInternal(
157 const std::string& method,
158 const base::DictionaryValue& params,
159 scoped_ptr<base::DictionaryValue>* result) {
160 if (!socket_->IsConnected())
161 return Status(kDisconnected, "not connected to DevTools");
162
163 int command_id = next_id_++;
164 base::DictionaryValue command;
165 command.SetInteger("id", command_id);
166 command.SetString("method", method);
167 command.Set("params", params.DeepCopy());
168 std::string message;
169 base::JSONWriter::Write(&command, &message);
170 if (!socket_->Send(message))
171 return Status(kDisconnected, "unable to send message to renderer");
172 return ReceiveCommandResponse(command_id, result);
173 }
174
175 Status DevToolsClientImpl::ReceiveCommandResponse(
176 int command_id,
177 scoped_ptr<base::DictionaryValue>* result) {
178 internal::InspectorMessageType type;
179 internal::InspectorEvent event;
180 internal::InspectorCommandResponse response;
181 cmd_response_map_[command_id] = NULL;
182 while (!HasReceivedCommandResponse(command_id)) {
183 Status status = ReceiveNextMessage(command_id, &type, &event, &response);
184 if (status.IsError())
185 return status;
186 }
187 result->reset(cmd_response_map_[command_id]);
188 cmd_response_map_.erase(command_id);
189 return Status(kOk);
190 }
191
192 Status DevToolsClientImpl::ReceiveNextMessage(
193 int expected_id,
194 internal::InspectorMessageType* type,
195 internal::InspectorEvent* event,
196 internal::InspectorCommandResponse* response) {
197 Status status = EnsureAllListenersNotifiedOfConnection();
198 if (status.IsError())
199 return status;
200
201 // The message might be received already when processing other commands sent
202 // from DevToolsEventListener::OnConnected.
203 if (HasReceivedCommandResponse(expected_id))
204 return Status(kOk);
205
206 std::string message;
207 if (!socket_->ReceiveNextMessage(&message))
208 return Status(kDisconnected, "unable to receive message from renderer");
209 if (!parser_func_.Run(message, expected_id, type, event, response))
210 return Status(kUnknownError, "bad inspector message: " + message);
211 if (*type == internal::kEventMessageType)
212 return NotifyEventListeners(event->method, *event->params);
213 if (*type == internal::kCommandResponseMessageType) {
214 if (cmd_response_map_.count(response->id) == 0) {
215 return Status(kUnknownError, "unexpected command message");
216 } else if (response->result) {
217 cmd_response_map_[response->id] = response->result.release();
218 } else {
219 cmd_response_map_.erase(response->id);
220 return ParseInspectorError(response->error);
221 }
222 }
223 return Status(kOk);
224 }
225
226 bool DevToolsClientImpl::HasReceivedCommandResponse(int cmd_id) {
227 return cmd_response_map_.find(cmd_id) != cmd_response_map_.end()
228 && cmd_response_map_[cmd_id] != NULL;
229 }
230
231 Status DevToolsClientImpl::NotifyEventListeners(
232 const std::string& method,
233 const base::DictionaryValue& params) {
234 for (std::list<DevToolsEventListener*>::iterator iter = listeners_.begin();
235 iter != listeners_.end(); ++iter) {
236 (*iter)->OnEvent(method, params);
237 }
238 if (method == "Inspector.detached")
239 return Status(kDisconnected, "received Inspector.detached event");
240 return Status(kOk);
241 }
242
243 Status DevToolsClientImpl::EnsureAllListenersNotifiedOfConnection() {
244 while (!listeners_for_on_connected_.empty()) {
245 DevToolsEventListener* listener = listeners_for_on_connected_.front();
246 listeners_for_on_connected_.pop_front();
247 Status status = listener->OnConnected();
248 if (status.IsError())
249 return status;
250 }
251 return Status(kOk);
252 }
253
254 namespace internal {
255
256 bool ParseInspectorMessage(
257 const std::string& message,
258 int expected_id,
259 InspectorMessageType* type,
260 InspectorEvent* event,
261 InspectorCommandResponse* command_response) {
262 scoped_ptr<base::Value> message_value(base::JSONReader::Read(message));
263 base::DictionaryValue* message_dict;
264 if (!message_value || !message_value->GetAsDictionary(&message_dict))
265 return false;
266
267 int id;
268 if (!message_dict->HasKey("id")) {
269 std::string method;
270 if (!message_dict->GetString("method", &method))
271 return false;
272 base::DictionaryValue* params = NULL;
273 message_dict->GetDictionary("params", &params);
274
275 *type = kEventMessageType;
276 event->method = method;
277 if (params)
278 event->params.reset(params->DeepCopy());
279 else
280 event->params.reset(new base::DictionaryValue());
281 return true;
282 } else if (message_dict->GetInteger("id", &id)) {
283 base::DictionaryValue* unscoped_error = NULL;
284 base::DictionaryValue* unscoped_result = NULL;
285 if (!message_dict->GetDictionary("error", &unscoped_error) &&
286 !message_dict->GetDictionary("result", &unscoped_result))
287 return false;
288
289 *type = kCommandResponseMessageType;
290 command_response->id = id;
291 if (unscoped_result)
292 command_response->result.reset(unscoped_result->DeepCopy());
293 else
294 base::JSONWriter::Write(unscoped_error, &command_response->error);
295 return true;
296 }
297 return false;
298 }
299
300 } // namespace internal
OLDNEW
« no previous file with comments | « chrome/test/chromedriver/devtools_client_impl.h ('k') | chrome/test/chromedriver/devtools_client_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698