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