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 "base/utf_string_conversions.h"
6 #include "chrome/browser/browser_process.h"
7 #include "chrome/browser/utility_process_host.h"
8 #include "chrome/test/in_process_browser_test.h"
9 #include "chrome/test/ui_test_utils.h"
10 #include "content/browser/renderer_host/resource_dispatcher_host.h"
11 #include "content/common/indexed_db_key.h"
12 #include "content/common/serialized_script_value.h"
13 #include "googleurl/src/gurl.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSerializedScriptValue.h"
16 #include "webkit/glue/idb_bindings.h"
17 #include "webkit/glue/web_io_operators.h"
18
19 using WebKit::WebSerializedScriptValue;
20
21 // Sanity test, check the function call directly outside the sandbox.
TEST(IDBKeyPathWithoutSandbox,Value)22 TEST(IDBKeyPathWithoutSandbox, Value) {
23 char16 data[] = {0x0353,0x6f66,0x536f,0x7a03,0x6f6f,0x017b};
24 std::vector<WebSerializedScriptValue> serialized_values;
25 serialized_values.push_back(
26 WebSerializedScriptValue::fromString(string16(data, arraysize(data))));
27 serialized_values.push_back(
28 WebSerializedScriptValue::fromString(string16()));
29
30 std::vector<WebKit::WebIDBKey> values;
31 string16 key_path(UTF8ToUTF16("foo"));
32 bool error = webkit_glue::IDBKeysFromValuesAndKeyPath(
33 serialized_values, key_path, &values);
34
35 ASSERT_EQ(size_t(2), values.size());
36 ASSERT_EQ(WebKit::WebIDBKey::StringType, values[0].type());
37 ASSERT_EQ(UTF8ToUTF16("zoo"), values[0].string());
38 ASSERT_EQ(WebKit::WebIDBKey::InvalidType, values[1].type());
39 ASSERT_FALSE(error);
40
41 values.clear();
42 key_path = UTF8ToUTF16("PropertyNotAvailable");
43 error = webkit_glue::IDBKeysFromValuesAndKeyPath(
44 serialized_values, key_path, &values);
45
46 ASSERT_EQ(size_t(2), values.size());
47 ASSERT_EQ(WebKit::WebIDBKey::InvalidType, values[0].type());
48 ASSERT_EQ(WebKit::WebIDBKey::InvalidType, values[1].type());
49 ASSERT_FALSE(error);
50
51 values.clear();
52 key_path = UTF8ToUTF16("!+Invalid[KeyPath[[[");
53 error = webkit_glue::IDBKeysFromValuesAndKeyPath(
54 serialized_values, key_path, &values);
55
56 ASSERT_TRUE(error);
57 ASSERT_EQ(size_t(2), values.size());
58 ASSERT_EQ(WebKit::WebIDBKey::InvalidType, values[0].type());
59 ASSERT_EQ(WebKit::WebIDBKey::InvalidType, values[1].type());
60 }
61
62 class IDBKeyPathHelper : public UtilityProcessHost::Client {
63 public:
IDBKeyPathHelper()64 IDBKeyPathHelper()
65 : expected_id_(0),
66 utility_process_host_(NULL),
67 value_for_key_path_failed_(false) {
68 }
69
CreateUtilityProcess()70 void CreateUtilityProcess() {
71 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
72 BrowserThread::PostTask(
73 BrowserThread::IO, FROM_HERE,
74 NewRunnableMethod(this, &IDBKeyPathHelper::CreateUtilityProcess));
75 return;
76 }
77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
78 utility_process_host_ =
79 new UtilityProcessHost(this, BrowserThread::IO);
80 utility_process_host_->StartBatchMode();
81 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
82 new MessageLoop::QuitTask());
83 }
84
DestroyUtilityProcess()85 void DestroyUtilityProcess() {
86 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
87 BrowserThread::PostTask(
88 BrowserThread::IO, FROM_HERE,
89 NewRunnableMethod(this, &IDBKeyPathHelper::DestroyUtilityProcess));
90 return;
91 }
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
93 utility_process_host_->EndBatchMode();
94 utility_process_host_ = NULL;
95 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
96 new MessageLoop::QuitTask());
97 }
98
SetExpectedKeys(int expected_id,const std::vector<IndexedDBKey> & expected_keys,bool failed)99 void SetExpectedKeys(int expected_id,
100 const std::vector<IndexedDBKey>& expected_keys,
101 bool failed) {
102 expected_id_ = expected_id;
103 expected_keys_ = expected_keys;
104 value_for_key_path_failed_ = failed;
105 }
106
SetExpectedValue(const SerializedScriptValue & expected_value)107 void SetExpectedValue(const SerializedScriptValue& expected_value) {
108 expected_value_ = expected_value;
109 }
110
CheckValuesForKeyPath(int id,const std::vector<SerializedScriptValue> & serialized_values,const string16 & key_path)111 void CheckValuesForKeyPath(
112 int id, const std::vector<SerializedScriptValue>& serialized_values,
113 const string16& key_path) {
114 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
115 BrowserThread::PostTask(
116 BrowserThread::IO, FROM_HERE,
117 NewRunnableMethod(this, &IDBKeyPathHelper::CheckValuesForKeyPath,
118 id, serialized_values, key_path));
119 return;
120 }
121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
122 bool ret =
123 utility_process_host_->StartIDBKeysFromValuesAndKeyPath(
124 id, serialized_values, key_path);
125 ASSERT_TRUE(ret);
126 }
127
CheckInjectValue(const IndexedDBKey & key,const SerializedScriptValue & value,const string16 & key_path)128 void CheckInjectValue(const IndexedDBKey& key,
129 const SerializedScriptValue& value,
130 const string16& key_path) {
131 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
132 BrowserThread::PostTask(
133 BrowserThread::IO, FROM_HERE,
134 NewRunnableMethod(this, &IDBKeyPathHelper::CheckInjectValue,
135 key, value, key_path));
136 return;
137 }
138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
139 bool ret = utility_process_host_->StartInjectIDBKey(key, value, key_path);
140 ASSERT_TRUE(ret);
141 }
142
143 // UtilityProcessHost::Client
OnIDBKeysFromValuesAndKeyPathSucceeded(int id,const std::vector<IndexedDBKey> & values)144 virtual void OnIDBKeysFromValuesAndKeyPathSucceeded(
145 int id, const std::vector<IndexedDBKey>& values) {
146 EXPECT_EQ(expected_id_, id);
147 EXPECT_FALSE(value_for_key_path_failed_);
148 ASSERT_EQ(expected_keys_.size(), values.size());
149 size_t pos = 0;
150 for (std::vector<IndexedDBKey>::const_iterator i(values.begin());
151 i != values.end(); ++i, ++pos) {
152 ASSERT_EQ(expected_keys_[pos].type(), i->type());
153 if (i->type() == WebKit::WebIDBKey::StringType) {
154 ASSERT_EQ(expected_keys_[pos].string(), i->string());
155 } else if (i->type() == WebKit::WebIDBKey::NumberType) {
156 ASSERT_EQ(expected_keys_[pos].number(), i->number());
157 }
158 }
159 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
160 new MessageLoop::QuitTask());
161 }
162
OnIDBKeysFromValuesAndKeyPathFailed(int id)163 virtual void OnIDBKeysFromValuesAndKeyPathFailed(int id) {
164 EXPECT_TRUE(value_for_key_path_failed_);
165 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
166 new MessageLoop::QuitTask());
167 }
168
OnInjectIDBKeyFinished(const SerializedScriptValue & new_value)169 virtual void OnInjectIDBKeyFinished(
170 const SerializedScriptValue& new_value) {
171 EXPECT_EQ(expected_value_.data(), new_value.data());
172 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
173 new MessageLoop::QuitTask());
174 }
175
176
177 private:
178 int expected_id_;
179 std::vector<IndexedDBKey> expected_keys_;
180 UtilityProcessHost* utility_process_host_;
181 bool value_for_key_path_failed_;
182 SerializedScriptValue expected_value_;
183 };
184
185 // This test fixture runs in the UI thread. However, most of the work done by
186 // UtilityProcessHost (and wrapped by IDBKeyPathHelper above) happens on the IO
187 // thread. This fixture delegates to IDBKeyPathHelper and blocks via
188 // "ui_test_utils::RunMessageLoop()", until IDBKeyPathHelper posts a quit
189 // message the MessageLoop.
190 class ScopedIDBKeyPathHelper {
191 public:
ScopedIDBKeyPathHelper()192 ScopedIDBKeyPathHelper() {
193 key_path_helper_ = new IDBKeyPathHelper();
194 key_path_helper_->CreateUtilityProcess();
195 ui_test_utils::RunMessageLoop();
196 }
197
~ScopedIDBKeyPathHelper()198 ~ScopedIDBKeyPathHelper() {
199 key_path_helper_->DestroyUtilityProcess();
200 ui_test_utils::RunMessageLoop();
201 }
202
SetExpectedKeys(int id,const std::vector<IndexedDBKey> & expected_keys,bool failed)203 void SetExpectedKeys(int id, const std::vector<IndexedDBKey>& expected_keys,
204 bool failed) {
205 key_path_helper_->SetExpectedKeys(id, expected_keys, failed);
206 }
207
SetExpectedValue(const SerializedScriptValue & expected_value)208 void SetExpectedValue(const SerializedScriptValue& expected_value) {
209 key_path_helper_->SetExpectedValue(expected_value);
210 }
211
CheckValuesForKeyPath(int id,const std::vector<SerializedScriptValue> & serialized_script_values,const string16 & key_path)212 void CheckValuesForKeyPath(
213 int id,
214 const std::vector<SerializedScriptValue>& serialized_script_values,
215 const string16& key_path) {
216 key_path_helper_->CheckValuesForKeyPath(id, serialized_script_values,
217 key_path);
218 ui_test_utils::RunMessageLoop();
219 }
220
CheckInjectValue(const IndexedDBKey & key,const SerializedScriptValue & value,const string16 & key_path)221 void CheckInjectValue(const IndexedDBKey& key,
222 const SerializedScriptValue& value,
223 const string16& key_path) {
224 key_path_helper_->CheckInjectValue(key, value, key_path);
225 ui_test_utils::RunMessageLoop();
226 }
227
228 private:
229 scoped_refptr<IDBKeyPathHelper> key_path_helper_;
230 };
231
IN_PROC_BROWSER_TEST_F(InProcessBrowserTest,IDBKeyPathExtract)232 IN_PROC_BROWSER_TEST_F(InProcessBrowserTest, IDBKeyPathExtract) {
233 ScopedIDBKeyPathHelper scoped_helper;
234 const int kId = 7;
235 std::vector<IndexedDBKey> expected_keys;
236 IndexedDBKey value;
237 value.SetString(UTF8ToUTF16("zoo"));
238 expected_keys.push_back(value);
239
240 IndexedDBKey invalid_value;
241 invalid_value.SetInvalid();
242 expected_keys.push_back(invalid_value);
243
244 scoped_helper.SetExpectedKeys(kId, expected_keys, false);
245
246 char16 data[] = {0x0353,0x6f66,0x536f,0x7a03,0x6f6f,0x017b};
247 std::vector<SerializedScriptValue> serialized_values;
248 serialized_values.push_back(
249 SerializedScriptValue(false, false, string16(data, arraysize(data))));
250 serialized_values.push_back(
251 SerializedScriptValue(true, false, string16()));
252 scoped_helper.CheckValuesForKeyPath(
253 kId, serialized_values, UTF8ToUTF16("foo"));
254 }
255
IN_PROC_BROWSER_TEST_F(InProcessBrowserTest,IDBKeyPathPropertyNotAvailable)256 IN_PROC_BROWSER_TEST_F(InProcessBrowserTest, IDBKeyPathPropertyNotAvailable) {
257 ScopedIDBKeyPathHelper scoped_helper;
258 const int kId = 7;
259 std::vector<IndexedDBKey> expected_keys;
260 IndexedDBKey invalid_value;
261 invalid_value.SetInvalid();
262 expected_keys.push_back(invalid_value);
263 expected_keys.push_back(invalid_value);
264
265 scoped_helper.SetExpectedKeys(kId, expected_keys, false);
266
267 char16 data[] = {0x0353,0x6f66,0x536f,0x7a03,0x6f6f,0x017b};
268 std::vector<SerializedScriptValue> serialized_values;
269 serialized_values.push_back(
270 SerializedScriptValue(false, false, string16(data, arraysize(data))));
271 serialized_values.push_back(
272 SerializedScriptValue(true, false, string16()));
273 scoped_helper.CheckValuesForKeyPath(kId, serialized_values,
274 UTF8ToUTF16("PropertyNotAvailable"));
275 }
276
IN_PROC_BROWSER_TEST_F(InProcessBrowserTest,IDBKeyPathMultipleCalls)277 IN_PROC_BROWSER_TEST_F(InProcessBrowserTest, IDBKeyPathMultipleCalls) {
278 ScopedIDBKeyPathHelper scoped_helper;
279 const int kId = 7;
280 std::vector<IndexedDBKey> expected_keys;
281 IndexedDBKey invalid_value;
282 invalid_value.SetInvalid();
283 expected_keys.push_back(invalid_value);
284 expected_keys.push_back(invalid_value);
285
286 scoped_helper.SetExpectedKeys(kId, expected_keys, true);
287
288 char16 data[] = {0x0353,0x6f66,0x536f,0x7a03,0x6f6f,0x017b};
289 std::vector<SerializedScriptValue> serialized_values;
290 serialized_values.push_back(
291 SerializedScriptValue(false, false, string16(data, arraysize(data))));
292 serialized_values.push_back(
293 SerializedScriptValue(true, false, string16()));
294 scoped_helper.CheckValuesForKeyPath(kId, serialized_values,
295 UTF8ToUTF16("!+Invalid[KeyPath[[["));
296
297 // Call again with the Utility process in batch mode and with valid keys.
298 expected_keys.clear();
299 IndexedDBKey value;
300 value.SetString(UTF8ToUTF16("zoo"));
301 expected_keys.push_back(value);
302 expected_keys.push_back(invalid_value);
303 scoped_helper.SetExpectedKeys(kId + 1, expected_keys, false);
304 scoped_helper.CheckValuesForKeyPath(kId + 1, serialized_values,
305 UTF8ToUTF16("foo"));
306 }
307
IN_PROC_BROWSER_TEST_F(InProcessBrowserTest,InjectIDBKey)308 IN_PROC_BROWSER_TEST_F(InProcessBrowserTest, InjectIDBKey) {
309 // {foo: 'zoo'}
310 const char16 data[] = {0x0353,0x6f66,0x536f,0x7a03,0x6f6f,0x017b};
311 SerializedScriptValue value(false, false, string16(data, arraysize(data)));
312 IndexedDBKey key;
313 key.SetString(UTF8ToUTF16("myNewKey"));
314
315 // {foo: 'zoo', bar: 'myNewKey'}
316 const char16 expected_data[] = {0x353, 0x6f66, 0x536f, 0x7a03, 0x6f6f, 0x353,
317 0x6162, 0x5372, 0x6d08, 0x4e79, 0x7765,
318 0x654b, 0x7b79, 0x2};
319 SerializedScriptValue expected_value(false, false,
320 string16(expected_data,
321 arraysize(expected_data)));
322
323 ScopedIDBKeyPathHelper scoped_helper;
324 scoped_helper.SetExpectedValue(expected_value);
325 scoped_helper.CheckInjectValue(key, value, UTF8ToUTF16("bar"));
326
327 scoped_helper.SetExpectedValue(SerializedScriptValue()); // Expect null.
328 scoped_helper.CheckInjectValue(key, value, UTF8ToUTF16("bad.key.path"));
329 }
330