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

Side by Side Diff: chrome/test/webdriver/webdriver_capabilities_parser.cc

Issue 8341044: Enhance and refactor ChromeDriver's capability handling. Log warning for (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ... Created 9 years, 1 month 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) 2011 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/webdriver_capabilities_parser.h"
6
7 #include "base/base64.h"
8 #include "base/file_util.h"
9 #include "base/logging.h"
10 #include "base/stringprintf.h"
11 #include "base/values.h"
12 #include "chrome/common/zip.h"
13 #include "chrome/test/webdriver/webdriver_error.h"
14 #include "chrome/test/webdriver/webdriver_util.h"
15
16 using base::Value;
17
18 namespace webdriver {
19
20 namespace {
21
22 bool WriteBase64DataToFile(const FilePath& filename,
23 const std::string& base64data,
24 std::string* error_msg) {
25 std::string data;
26 if (!base::Base64Decode(base64data, &data)) {
27 *error_msg = "Invalid base64 encoded data.";
28 return false;
29 }
30 if (!file_util::WriteFile(filename, data.c_str(), data.length())) {
31 *error_msg = "Could not write data to file.";
32 return false;
33 }
34 return true;
35 }
36
37 Error* CreateBadInputError(const std::string& name,
38 Value::Type type,
39 const Value* option) {
40 return new Error(kBadRequest, base::StringPrintf(
41 "%s must be of type %s, not %s",
42 name.c_str(), GetJsonTypeName(type),
43 GetJsonTypeName(option->GetType())));
44 }
45
46 } // namespace
47
48 Capabilities::Capabilities()
49 : command(CommandLine::NO_PROGRAM),
50 detach(false),
51 load_async(false),
52 native_events(false),
53 verbose(false) { }
54
55 Capabilities::~Capabilities() { }
56
57 CapabilitiesParser::CapabilitiesParser(
58 const base::DictionaryValue* capabilities_dict,
59 const FilePath& root_path,
60 Capabilities* capabilities)
61 : dict_(capabilities_dict),
62 root_(root_path),
63 caps_(capabilities) {
64 }
65
66 CapabilitiesParser::~CapabilitiesParser() { }
67
68 Error* CapabilitiesParser::Parse() {
69 const char kOptionsKey[] = "chromeOptions";
70 bool legacy_options = !dict_->HasKey(kOptionsKey);
71 const base::DictionaryValue* options = dict_;
72 if (!legacy_options) {
73 base::DictionaryValue* non_const_options;
74 if (!dict_->GetDictionaryWithoutPathExpansion(
75 kOptionsKey, &non_const_options)) {
76 return new Error(kBadRequest, base::StringPrintf(
77 "'%s' must be a dictionary.", kOptionsKey));
78 }
79 options = non_const_options;
80 }
81
82 typedef Error* (CapabilitiesParser::*Parser)(const Value*);
83 std::map<std::string, Parser> parser_map;
84 if (legacy_options) {
85 parser_map["chrome.binary"] = &CapabilitiesParser::ParseBinary;
86 parser_map["chrome.channel"] = &CapabilitiesParser::ParseChannel;
87 parser_map["chrome.detach"] = &CapabilitiesParser::ParseDetach;
88 parser_map["chrome.extensions"] = &CapabilitiesParser::ParseExtensions;
89 parser_map["chrome.loadAsync"] = &CapabilitiesParser::ParseLoadAsync;
90 parser_map["chrome.nativeEvents"] = &CapabilitiesParser::ParseNativeEvents;
91 parser_map["chrome.profile"] = &CapabilitiesParser::ParseProfile;
92 parser_map["chrome.switches"] = &CapabilitiesParser::ParseArgs;
93 parser_map["chrome.verbose"] = &CapabilitiesParser::ParseVerbose;
94 } else {
95 parser_map["args"] = &CapabilitiesParser::ParseArgs;
96 parser_map["binary"] = &CapabilitiesParser::ParseBinary;
97 parser_map["channel"] = &CapabilitiesParser::ParseChannel;
98 parser_map["detach"] = &CapabilitiesParser::ParseDetach;
99 parser_map["extensions"] = &CapabilitiesParser::ParseExtensions;
100 parser_map["loadAsync"] = &CapabilitiesParser::ParseLoadAsync;
101 parser_map["nativeEvents"] = &CapabilitiesParser::ParseNativeEvents;
102 parser_map["profile"] = &CapabilitiesParser::ParseProfile;
103 parser_map["verbose"] = &CapabilitiesParser::ParseVerbose;
104 }
105
106 base::DictionaryValue::key_iterator key_iter = options->begin_keys();
107 for (; key_iter != options->end_keys(); ++key_iter) {
108 if (parser_map.find(*key_iter) == parser_map.end()) {
109 LOG(WARNING) << "Ignoring unrecognized capability: " << *key_iter;
110 continue;
111 }
112 Value* option = NULL;
113 options->GetWithoutPathExpansion(*key_iter, &option);
114 Error* error = (this->*parser_map[*key_iter])(option);
115 if (error) {
116 error->AddDetails(base::StringPrintf(
117 "Error occurred while processing capability '%s'",
118 (*key_iter).c_str()));
119 return error;
120 }
121 }
122 return NULL;
123 }
124
125 Error* CapabilitiesParser::ParseArgs(const Value* option) {
126 const base::ListValue* args;
127 if (!option->GetAsList(&args))
128 return CreateBadInputError("arguments", Value::TYPE_LIST, option);
129 for (size_t i = 0; i < args->GetSize(); ++i) {
130 std::string arg_string;
131 if (!args->GetString(i, &arg_string))
132 return CreateBadInputError("argument", Value::TYPE_STRING, option);
133 size_t separator_index = arg_string.find("=");
134 if (separator_index != std::string::npos) {
135 CommandLine::StringType arg_string_native;
136 if (!args->GetString(i, &arg_string_native))
137 return CreateBadInputError("argument", Value::TYPE_STRING, option);
138 caps_->command.AppendSwitchNative(
139 arg_string.substr(0, separator_index),
140 arg_string_native.substr(separator_index + 1));
141 } else {
142 caps_->command.AppendSwitch(arg_string);
143 }
144 }
145 return NULL;
146 }
147
148 Error* CapabilitiesParser::ParseBinary(const Value* option) {
149 FilePath::StringType path;
150 if (!option->GetAsString(&path)) {
151 return CreateBadInputError("binary path", Value::TYPE_STRING, option);
152 }
153 caps_->command.SetProgram(FilePath(path));
154 return NULL;
155 }
156
157 Error* CapabilitiesParser::ParseChannel(const Value* option) {
158 if (!option->GetAsString(&caps_->channel))
159 return CreateBadInputError("channel", Value::TYPE_STRING, option);
160 return NULL;
161 }
162
163 Error* CapabilitiesParser::ParseDetach(const Value* option) {
164 if (!option->GetAsBoolean(&caps_->detach))
165 return CreateBadInputError("detach", Value::TYPE_BOOLEAN, option);
166 return NULL;
167 }
168
169 Error* CapabilitiesParser::ParseExtensions(const Value* option) {
170 const base::ListValue* extensions;
171 if (!option->GetAsList(&extensions))
172 return CreateBadInputError("extensions", Value::TYPE_LIST, option);
173 for (size_t i = 0; i < extensions->GetSize(); ++i) {
174 std::string extension_base64;
175 if (!extensions->GetString(i, &extension_base64)) {
176 return new Error(kBadRequest,
177 "Each extension must be a base64 encoded string");
178 }
179 FilePath extension;
180 std::string error_msg;
181 if (!DecodeAndWriteFile(extension_base64, false /* unzip */,
182 &extension, &error_msg)) {
183 return new Error(
184 kUnknownError,
185 "Error occurred while parsing extension: " + error_msg);
186 }
187 caps_->extensions.push_back(extension);
188 }
189 return NULL;
190 }
191
192 Error* CapabilitiesParser::ParseLoadAsync(const Value* option) {
193 if (!option->GetAsBoolean(&caps_->load_async))
194 return CreateBadInputError("loadAsync", Value::TYPE_BOOLEAN, option);
195 return NULL;
196 }
197
198 Error* CapabilitiesParser::ParseNativeEvents(const Value* option) {
199 if (!option->GetAsBoolean(&caps_->native_events))
200 return CreateBadInputError("nativeEvents", Value::TYPE_BOOLEAN, option);
201 return NULL;
202 }
203
204 Error* CapabilitiesParser::ParseProfile(const Value* option) {
205 std::string profile_base64;
206 if (!option->GetAsString(&profile_base64))
207 return CreateBadInputError("profile", Value::TYPE_STRING, option);
208 std::string error_msg;
209 if (!DecodeAndWriteFile(profile_base64, true /* unzip */,
210 &caps_->profile, &error_msg))
211 return new Error(kUnknownError, "unable to unpack profile: " + error_msg);
212 return NULL;
213 }
214
215 Error* CapabilitiesParser::ParseVerbose(const Value* option) {
216 if (!option->GetAsBoolean(&caps_->verbose))
217 return CreateBadInputError("verbose", Value::TYPE_BOOLEAN, option);
218 return NULL;
219 }
220
221 bool CapabilitiesParser::DecodeAndWriteFile(
222 const std::string& base64,
223 bool unzip,
224 FilePath* path,
225 std::string* error_msg) {
226 FilePath base64_path = root_.AppendASCII(GenerateRandomID());
227 if (!WriteBase64DataToFile(base64_path, base64, error_msg))
228 return false;
229
230 if (unzip) {
231 FilePath unzipped_path = root_.AppendASCII(GenerateRandomID());
232 if (!Unzip(base64_path, unzipped_path)) {
233 *error_msg = "Failed to unzip archive";
234 return false;
235 }
236 *path = unzipped_path;
237 } else {
238 *path = base64_path;
239 }
240 return true;
241 }
242
243 } // namespace webdriver
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698