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/webdriver/commands/chrome_commands.h"
6
7#include <string>
8#include <vector>
9
10#include "base/files/file_path.h"
11#include "base/strings/stringprintf.h"
12#include "chrome/test/automation/value_conversion_util.h"
13#include "chrome/test/webdriver/commands/response.h"
14#include "chrome/test/webdriver/webdriver_error.h"
15#include "chrome/test/webdriver/webdriver_session.h"
16#include "chrome/test/webdriver/webdriver_util.h"
17
18using base::DictionaryValue;
19using base::ListValue;
20using base::Value;
21
22namespace webdriver {
23
24ExtensionsCommand::ExtensionsCommand(
25    const std::vector<std::string>& path_segments,
26    const DictionaryValue* const parameters)
27    : WebDriverCommand(path_segments, parameters) {}
28
29ExtensionsCommand::~ExtensionsCommand() {}
30
31bool ExtensionsCommand::DoesGet() {
32  return true;
33}
34
35bool ExtensionsCommand::DoesPost() {
36  return true;
37}
38
39void ExtensionsCommand::ExecuteGet(Response* const response) {
40  ListValue extensions_list;
41  Error* error = session_->GetExtensionsInfo(&extensions_list);
42  if (error) {
43    response->SetError(error);
44    return;
45  }
46
47  ListValue id_list;
48  for (size_t i = 0; i < extensions_list.GetSize(); ++i) {
49    DictionaryValue* extension_dict;
50    if (!extensions_list.GetDictionary(i, &extension_dict)) {
51      response->SetError(
52          new Error(kUnknownError, "Invalid extension dictionary"));
53      return;
54    }
55    bool is_component;
56    if (!extension_dict->GetBoolean("is_component", &is_component)) {
57      response->SetError(
58          new Error(kUnknownError, "Missing or invalid 'is_component'"));
59      return;
60    }
61    if (is_component)
62      continue;
63
64    std::string extension_id;
65    if (!extension_dict->GetString("id", &extension_id)) {
66      response->SetError(new Error(kUnknownError, "Missing or invalid 'id'"));
67      return;
68    }
69
70    id_list.Append(new base::StringValue(extension_id));
71  }
72
73  response->SetValue(id_list.DeepCopy());
74}
75
76void ExtensionsCommand::ExecutePost(Response* const response) {
77  base::FilePath::StringType path_string;
78  if (!GetStringParameter("path", &path_string)) {
79    response->SetError(new Error(kBadRequest, "'path' missing or invalid"));
80    return;
81  }
82
83  std::string extension_id;
84  Error* error = session_->InstallExtension(
85      base::FilePath(path_string), &extension_id);
86  if (error) {
87    response->SetError(error);
88    return;
89  }
90  response->SetValue(new base::StringValue(extension_id));
91}
92
93ExtensionCommand::ExtensionCommand(
94    const std::vector<std::string>& path_segments,
95    const DictionaryValue* const parameters)
96    : WebDriverCommand(path_segments, parameters) {}
97
98ExtensionCommand::~ExtensionCommand() {}
99
100bool ExtensionCommand::Init(Response* const response) {
101  if (!WebDriverCommand::Init(response))
102    return false;
103
104  // Path: "/session/$sessionId/chrome/extension/$id".
105  extension_id_ = GetPathVariable(5);
106  if (extension_id_.empty()) {
107    response->SetError(new Error(kBadRequest, "Invalid extension ID"));
108    return false;
109  }
110  return true;
111}
112
113bool ExtensionCommand::DoesGet() {
114  return true;
115}
116
117bool ExtensionCommand::DoesPost() {
118  return true;
119}
120
121bool ExtensionCommand::DoesDelete() {
122  return true;
123}
124
125void ExtensionCommand::ExecuteGet(Response* const response) {
126  ListValue extensions_list;
127  Error* error = session_->GetExtensionsInfo(&extensions_list);
128  if (error) {
129    response->SetError(error);
130    return;
131  }
132
133  bool found = false;
134  DictionaryValue extension;
135  for (size_t i = 0; i < extensions_list.GetSize(); ++i) {
136    DictionaryValue* extension_dict;
137    if (!extensions_list.GetDictionary(i, &extension_dict)) {
138      response->SetError(
139          new Error(kUnknownError, "Invalid extension dictionary"));
140      return;
141    }
142    std::string id;
143    if (!extension_dict->GetString("id", &id)) {
144      response->SetError(
145          new Error(kUnknownError, "Missing extension ID"));
146      return;
147    }
148    if (id == extension_id_) {
149      found = true;
150      extension.Swap(extension_dict);
151      break;
152    }
153  }
154
155  if (!found) {
156    response->SetError(
157        new Error(kUnknownError, "Extension is not installed"));
158    return;
159  }
160
161  bool is_enabled;
162  if (!extension.GetBoolean("is_enabled", &is_enabled)) {
163    response->SetError(
164        new Error(kUnknownError, "Missing or invalid 'is_enabled'"));
165    return;
166  }
167  bool has_page_action;
168  if (!extension.GetBoolean("has_page_action", &has_page_action)) {
169    response->SetError(
170        new Error(kUnknownError, "Missing or invalid 'is_enabled'"));
171    return;
172  }
173
174  bool is_visible = false;
175  if (is_enabled && has_page_action) {
176    // Only check page action visibility if we are enabled with a page action.
177    // Otherwise Chrome will throw an error saying the extension does not have
178    // a page action.
179    error = session_->IsPageActionVisible(
180        session_->current_target().view_id, extension_id_, &is_visible);
181    if (error) {
182      response->SetError(error);
183      return;
184    }
185  }
186
187  extension.SetBoolean("is_page_action_visible", is_visible);
188  response->SetValue(extension.DeepCopy());
189}
190
191void ExtensionCommand::ExecutePost(Response* const response) {
192  Error* error = NULL;
193  if (HasParameter("enable")) {
194    bool enable;
195    if (!GetBooleanParameter("enable", &enable)) {
196      response->SetError(new Error(kBadRequest, "'enable' must be a bool"));
197      return;
198    }
199    error = session_->SetExtensionState(extension_id_, enable);
200  } else if (HasParameter("click_button")) {
201    std::string button;
202    if (!GetStringParameter("click_button", &button)) {
203      response->SetError(
204          new Error(kBadRequest, "'click_button' must be a string"));
205      return;
206    }
207    error = session_->ClickExtensionButton(extension_id_,
208                                           button == "browser_action");
209  } else {
210    error = new Error(kBadRequest, "Missing action parameter");
211  }
212
213  if (error) {
214    response->SetError(error);
215    return;
216  }
217}
218
219void ExtensionCommand::ExecuteDelete(Response* const response) {
220  Error* error = session_->UninstallExtension(extension_id_);
221  if (error) {
222    response->SetError(error);
223    return;
224  }
225}
226
227ViewsCommand::ViewsCommand(
228    const std::vector<std::string>& path_segments,
229    const DictionaryValue* const parameters)
230    : WebDriverCommand(path_segments, parameters) {}
231
232ViewsCommand::~ViewsCommand() {}
233
234bool ViewsCommand::DoesGet() {
235  return true;
236}
237
238void ViewsCommand::ExecuteGet(Response* const response) {
239  std::vector<WebViewInfo> views;
240  Error* error = session_->GetViews(&views);
241  if (error) {
242    response->SetError(error);
243    return;
244  }
245  ListValue* views_list = new ListValue();
246  for (size_t i = 0; i < views.size(); ++i) {
247    DictionaryValue* dict = new DictionaryValue();
248    AutomationId id = views[i].view_id.GetId();
249    dict->SetString("handle", WebViewIdToString(WebViewId::ForView(id)));
250    dict->SetInteger("type", id.type());
251    if (!views[i].extension_id.empty())
252      dict->SetString("extension_id", views[i].extension_id);
253    views_list->Append(dict);
254  }
255  response->SetValue(views_list);
256}
257
258#if !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS))
259HeapProfilerDumpCommand::HeapProfilerDumpCommand(
260    const std::vector<std::string>& ps,
261    const DictionaryValue* const parameters)
262    : WebDriverCommand(ps, parameters) {}
263
264HeapProfilerDumpCommand::~HeapProfilerDumpCommand() {}
265
266bool HeapProfilerDumpCommand::DoesPost() {
267  return true;
268}
269
270void HeapProfilerDumpCommand::ExecutePost(Response* const response) {
271  std::string reason;
272  if (!GetStringParameter("reason", &reason)) {
273    response->SetError(new Error(kBadRequest, "'reason' missing or invalid"));
274    return;
275  }
276
277  Error* error = session_->HeapProfilerDump(reason);
278  if (error) {
279    response->SetError(error);
280    return;
281  }
282}
283#endif  // !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS))
284
285}  // namespace webdriver
286