OLD | NEW |
| (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 "base/bind.h" | |
6 #include "base/message_loop.h" | |
7 #include "base/utf_string_conversions.h" | |
8 #include "content/browser/utility_process_host_impl.h" | |
9 #include "content/public/browser/utility_process_host_client.h" | |
10 #include "content/common/indexed_db/indexed_db_key.h" | |
11 #include "content/common/indexed_db/indexed_db_key_path.h" | |
12 #include "content/common/utility_messages.h" | |
13 #include "content/common/webkitplatformsupport_impl.h" | |
14 #include "content/public/common/serialized_script_value.h" | |
15 #include "content/public/test/test_utils.h" | |
16 #include "content/test/content_browser_test.h" | |
17 #include "googleurl/src/gurl.h" | |
18 #include "testing/gtest/include/gtest/gtest.h" | |
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h" | |
20 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSerialize
dScriptValue.h" | |
21 #include "webkit/glue/idb_bindings.h" | |
22 #include "webkit/glue/web_io_operators.h" | |
23 | |
24 using WebKit::WebSerializedScriptValue; | |
25 using WebKit::WebIDBKeyPath; | |
26 | |
27 namespace content { | |
28 | |
29 // Enables calling WebKit::shutdown no matter where a "return" happens. | |
30 class ScopedShutdownWebKit { | |
31 public: | |
32 ScopedShutdownWebKit() { | |
33 } | |
34 | |
35 ~ScopedShutdownWebKit() { | |
36 WebKit::shutdown(); | |
37 } | |
38 | |
39 private: | |
40 DISALLOW_COPY_AND_ASSIGN(ScopedShutdownWebKit); | |
41 }; | |
42 | |
43 // Sanity test, check the function call directly outside the sandbox. | |
44 TEST(IDBKeyPathWithoutSandbox, Value) { | |
45 WebKitPlatformSupportImpl webkit_platform_support; | |
46 WebKit::initialize(&webkit_platform_support); | |
47 ScopedShutdownWebKit shutdown_webkit; | |
48 | |
49 // {foo: "zoo"} | |
50 char16 data_foo_zoo[] = {0x0353,0x6f66,0x536f,0x7a03,0x6f6f,0x017b}; | |
51 std::vector<WebSerializedScriptValue> serialized_values; | |
52 serialized_values.push_back( | |
53 WebSerializedScriptValue::fromString(string16(data_foo_zoo, | |
54 arraysize(data_foo_zoo)))); | |
55 | |
56 // {foo: null} | |
57 char16 data_foo_null[] = {0x0353, 0x6f66, 0x306f, 0x017b}; | |
58 serialized_values.push_back(SerializedScriptValue( | |
59 false, false, string16(data_foo_null, arraysize(data_foo_null)))); | |
60 | |
61 // {} | |
62 char16 data_object[] = {0x017b}; | |
63 serialized_values.push_back(SerializedScriptValue( | |
64 false, false, string16(data_object, arraysize(data_object)))); | |
65 | |
66 // null | |
67 serialized_values.push_back( | |
68 WebSerializedScriptValue::fromString(string16())); | |
69 | |
70 std::vector<WebKit::WebIDBKey> values; | |
71 IndexedDBKeyPath key_path; | |
72 | |
73 key_path.SetString(UTF8ToUTF16("foo")); | |
74 webkit_glue::IDBKeysFromValuesAndKeyPath( | |
75 serialized_values, key_path, &values); | |
76 | |
77 ASSERT_EQ(size_t(4), values.size()); | |
78 ASSERT_EQ(WebKit::WebIDBKey::StringType, values[0].type()); | |
79 ASSERT_EQ(UTF8ToUTF16("zoo"), values[0].string()); | |
80 ASSERT_EQ(WebKit::WebIDBKey::InvalidType, values[1].type()); | |
81 ASSERT_EQ(WebKit::WebIDBKey::NullType, values[2].type()); | |
82 ASSERT_EQ(WebKit::WebIDBKey::NullType, values[3].type()); | |
83 | |
84 values.clear(); | |
85 key_path.SetString(UTF8ToUTF16("PropertyNotAvailable")); | |
86 webkit_glue::IDBKeysFromValuesAndKeyPath( | |
87 serialized_values, key_path, &values); | |
88 | |
89 ASSERT_EQ(size_t(4), values.size()); | |
90 ASSERT_EQ(WebKit::WebIDBKey::NullType, values[0].type()); | |
91 ASSERT_EQ(WebKit::WebIDBKey::NullType, values[1].type()); | |
92 ASSERT_EQ(WebKit::WebIDBKey::NullType, values[2].type()); | |
93 ASSERT_EQ(WebKit::WebIDBKey::NullType, values[3].type()); | |
94 | |
95 values.clear(); | |
96 key_path.SetString(UTF8ToUTF16("!+Invalid[KeyPath[[[")); | |
97 ASSERT_FALSE(key_path.IsValid()); | |
98 } | |
99 | |
100 class IDBKeyPathHelper : public UtilityProcessHostClient { | |
101 public: | |
102 IDBKeyPathHelper() | |
103 : expected_id_(0), | |
104 value_for_key_path_failed_(false) { | |
105 } | |
106 | |
107 void CreateUtilityProcess() { | |
108 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
109 BrowserThread::PostTask( | |
110 BrowserThread::IO, FROM_HERE, | |
111 base::Bind(&IDBKeyPathHelper::CreateUtilityProcess, this)); | |
112 return; | |
113 } | |
114 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
115 utility_process_host_ = | |
116 (new UtilityProcessHostImpl(this, BrowserThread::IO))->AsWeakPtr(); | |
117 utility_process_host_->EnableZygote(); | |
118 utility_process_host_->StartBatchMode(); | |
119 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
120 MessageLoop::QuitClosure()); | |
121 } | |
122 | |
123 void DestroyUtilityProcess() { | |
124 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
125 BrowserThread::PostTask( | |
126 BrowserThread::IO, FROM_HERE, | |
127 base::Bind(&IDBKeyPathHelper::DestroyUtilityProcess, this)); | |
128 return; | |
129 } | |
130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
131 utility_process_host_->EndBatchMode(); | |
132 utility_process_host_.reset(); | |
133 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
134 MessageLoop::QuitClosure()); | |
135 } | |
136 | |
137 void SetExpectedKeys(int expected_id, | |
138 const std::vector<IndexedDBKey>& expected_keys, | |
139 bool failed) { | |
140 expected_id_ = expected_id; | |
141 expected_keys_ = expected_keys; | |
142 value_for_key_path_failed_ = failed; | |
143 } | |
144 | |
145 void SetExpectedValue(const SerializedScriptValue& expected_value) { | |
146 expected_value_ = expected_value; | |
147 } | |
148 | |
149 void CheckValuesForKeyPath( | |
150 int id, | |
151 const std::vector<SerializedScriptValue>& serialized_values, | |
152 const IndexedDBKeyPath& key_path) { | |
153 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
154 BrowserThread::PostTask( | |
155 BrowserThread::IO, FROM_HERE, | |
156 base::Bind(&IDBKeyPathHelper::CheckValuesForKeyPath, this, id, | |
157 serialized_values, key_path)); | |
158 return; | |
159 } | |
160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
161 bool ret = utility_process_host_->Send( | |
162 new UtilityMsg_IDBKeysFromValuesAndKeyPath( | |
163 id, serialized_values, key_path)); | |
164 ASSERT_TRUE(ret); | |
165 } | |
166 | |
167 void CheckInjectValue(const IndexedDBKey& key, | |
168 const SerializedScriptValue& value, | |
169 const IndexedDBKeyPath& key_path) { | |
170 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
171 BrowserThread::PostTask( | |
172 BrowserThread::IO, FROM_HERE, | |
173 base::Bind(&IDBKeyPathHelper::CheckInjectValue, this, key, value, | |
174 key_path)); | |
175 return; | |
176 } | |
177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
178 bool ret = utility_process_host_->Send(new UtilityMsg_InjectIDBKey( | |
179 key, value, key_path)); | |
180 ASSERT_TRUE(ret); | |
181 } | |
182 | |
183 // UtilityProcessHostClient | |
184 bool OnMessageReceived(const IPC::Message& message) { | |
185 bool msg_is_ok = true; | |
186 bool handled = true; | |
187 IPC_BEGIN_MESSAGE_MAP_EX(IDBKeyPathHelper, message, msg_is_ok) | |
188 IPC_MESSAGE_HANDLER(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Succeeded, | |
189 OnIDBKeysFromValuesAndKeyPathSucceeded) | |
190 IPC_MESSAGE_HANDLER(UtilityHostMsg_InjectIDBKey_Finished, | |
191 OnInjectIDBKeyFinished) | |
192 IPC_MESSAGE_UNHANDLED(handled = false) | |
193 IPC_END_MESSAGE_MAP_EX() | |
194 return handled; | |
195 } | |
196 | |
197 void OnIDBKeysFromValuesAndKeyPathSucceeded( | |
198 int id, const std::vector<IndexedDBKey>& values) { | |
199 EXPECT_EQ(expected_id_, id); | |
200 EXPECT_FALSE(value_for_key_path_failed_); | |
201 ASSERT_EQ(expected_keys_.size(), values.size()); | |
202 size_t pos = 0; | |
203 for (std::vector<IndexedDBKey>::const_iterator i(values.begin()); | |
204 i != values.end(); ++i, ++pos) { | |
205 ASSERT_EQ(expected_keys_[pos].type(), i->type()); | |
206 if (i->type() == WebKit::WebIDBKey::StringType) { | |
207 ASSERT_EQ(expected_keys_[pos].string(), i->string()); | |
208 } else if (i->type() == WebKit::WebIDBKey::NumberType) { | |
209 ASSERT_EQ(expected_keys_[pos].number(), i->number()); | |
210 } | |
211 } | |
212 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
213 MessageLoop::QuitClosure()); | |
214 } | |
215 | |
216 void OnIDBKeysFromValuesAndKeyPathFailed(int id) { | |
217 EXPECT_TRUE(value_for_key_path_failed_); | |
218 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
219 MessageLoop::QuitClosure()); | |
220 } | |
221 | |
222 void OnInjectIDBKeyFinished(const SerializedScriptValue& new_value) { | |
223 EXPECT_EQ(expected_value_.data(), new_value.data()); | |
224 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
225 MessageLoop::QuitClosure()); | |
226 } | |
227 | |
228 | |
229 private: | |
230 virtual ~IDBKeyPathHelper() {} | |
231 | |
232 int expected_id_; | |
233 std::vector<IndexedDBKey> expected_keys_; | |
234 base::WeakPtr<UtilityProcessHost> utility_process_host_; | |
235 bool value_for_key_path_failed_; | |
236 SerializedScriptValue expected_value_; | |
237 }; | |
238 | |
239 // This test fixture runs in the UI thread. However, most of the work done by | |
240 // UtilityProcessHost (and wrapped by IDBKeyPathHelper above) happens on the IO | |
241 // thread. This fixture delegates to IDBKeyPathHelper and blocks via | |
242 // "RunMessageLoop()", until IDBKeyPathHelper posts a quit | |
243 // message the MessageLoop. | |
244 class ScopedIDBKeyPathHelper { | |
245 public: | |
246 ScopedIDBKeyPathHelper() { | |
247 key_path_helper_ = new IDBKeyPathHelper(); | |
248 key_path_helper_->CreateUtilityProcess(); | |
249 RunMessageLoop(); | |
250 } | |
251 | |
252 ~ScopedIDBKeyPathHelper() { | |
253 key_path_helper_->DestroyUtilityProcess(); | |
254 RunMessageLoop(); | |
255 } | |
256 | |
257 void SetExpectedKeys(int id, | |
258 const std::vector<IndexedDBKey>& expected_keys, | |
259 bool failed) { | |
260 key_path_helper_->SetExpectedKeys(id, expected_keys, failed); | |
261 } | |
262 | |
263 void SetExpectedValue(const SerializedScriptValue& expected_value) { | |
264 key_path_helper_->SetExpectedValue(expected_value); | |
265 } | |
266 | |
267 void CheckValuesForKeyPath( | |
268 int id, | |
269 const std::vector<SerializedScriptValue>& | |
270 serialized_script_values, | |
271 const IndexedDBKeyPath& key_path) { | |
272 key_path_helper_->CheckValuesForKeyPath(id, serialized_script_values, | |
273 key_path); | |
274 RunMessageLoop(); | |
275 } | |
276 | |
277 void CheckInjectValue(const IndexedDBKey& key, | |
278 const SerializedScriptValue& value, | |
279 const IndexedDBKeyPath& key_path) { | |
280 key_path_helper_->CheckInjectValue(key, value, key_path); | |
281 RunMessageLoop(); | |
282 } | |
283 | |
284 private: | |
285 scoped_refptr<IDBKeyPathHelper> key_path_helper_; | |
286 }; | |
287 | |
288 // Cases: | |
289 IN_PROC_BROWSER_TEST_F(ContentBrowserTest, IDBKeyPathExtract) { | |
290 ScopedIDBKeyPathHelper scoped_helper; | |
291 const int kId = 7; | |
292 std::vector<IndexedDBKey> expected_keys; | |
293 std::vector<SerializedScriptValue> serialized_values; | |
294 | |
295 IndexedDBKey string_zoo_key; | |
296 string_zoo_key.SetString(UTF8ToUTF16("zoo")); | |
297 IndexedDBKey null_key; | |
298 null_key.SetNull(); | |
299 IndexedDBKey invalid_key; | |
300 invalid_key.SetInvalid(); | |
301 | |
302 // keypath: "foo", value: {foo: "zoo"}, expected: "zoo" | |
303 char16 data_foo_zoo[] = {0x0353,0x6f66,0x536f,0x7a03,0x6f6f,0x017b}; | |
304 serialized_values.push_back(SerializedScriptValue( | |
305 false, false, string16(data_foo_zoo, arraysize(data_foo_zoo)))); | |
306 expected_keys.push_back(string_zoo_key); | |
307 | |
308 // keypath: "foo", value: {foo: null}, expected: invalid | |
309 char16 data_foo_null[] = {0x0353, 0x6f66, 0x306f, 0x017b}; | |
310 serialized_values.push_back(SerializedScriptValue( | |
311 false, false, string16(data_foo_null, arraysize(data_foo_null)))); | |
312 expected_keys.push_back(invalid_key); | |
313 | |
314 // keypath: "foo", value: {}, expected: null | |
315 char16 data_object[] = {0x017b}; | |
316 serialized_values.push_back(SerializedScriptValue( | |
317 false, false, string16(data_object, arraysize(data_object)))); | |
318 expected_keys.push_back(null_key); | |
319 | |
320 // keypath: "foo", value: null, expected: null | |
321 serialized_values.push_back( | |
322 SerializedScriptValue(true, false, string16())); | |
323 expected_keys.push_back(null_key); | |
324 | |
325 scoped_helper.SetExpectedKeys(kId, expected_keys, false); | |
326 | |
327 IndexedDBKeyPath key_path; | |
328 key_path.SetString(UTF8ToUTF16("foo")); | |
329 scoped_helper.CheckValuesForKeyPath( | |
330 kId, serialized_values, key_path); | |
331 } | |
332 | |
333 IN_PROC_BROWSER_TEST_F(ContentBrowserTest, IDBKeyPathPropertyNotAvailable) { | |
334 ScopedIDBKeyPathHelper scoped_helper; | |
335 const int kId = 7; | |
336 std::vector<IndexedDBKey> expected_keys; | |
337 IndexedDBKey null_value; | |
338 null_value.SetNull(); | |
339 expected_keys.push_back(null_value); | |
340 expected_keys.push_back(null_value); | |
341 | |
342 scoped_helper.SetExpectedKeys(kId, expected_keys, false); | |
343 | |
344 std::vector<SerializedScriptValue> serialized_values; | |
345 // {foo: "zoo", bar: null} | |
346 char16 data[] = {0x0353, 0x6f66, 0x536f, 0x7a03, 0x6f6f, 0x0353, 0x6162, | |
347 0x3072, 0x027b}; | |
348 serialized_values.push_back(SerializedScriptValue( | |
349 false, false, string16(data, arraysize(data)))); | |
350 | |
351 // null | |
352 serialized_values.push_back( | |
353 SerializedScriptValue(true, false, string16())); | |
354 | |
355 IndexedDBKeyPath key_path; | |
356 key_path.SetString(UTF8ToUTF16("PropertyNotAvailable")); | |
357 scoped_helper.CheckValuesForKeyPath(kId, serialized_values, key_path); | |
358 } | |
359 | |
360 IN_PROC_BROWSER_TEST_F(ContentBrowserTest, IDBKeyPathMultipleCalls) { | |
361 ScopedIDBKeyPathHelper scoped_helper; | |
362 const int kId = 7; | |
363 std::vector<IndexedDBKey> expected_keys; | |
364 | |
365 IndexedDBKey null_value; | |
366 null_value.SetNull(); | |
367 expected_keys.push_back(null_value); | |
368 expected_keys.push_back(null_value); | |
369 scoped_helper.SetExpectedKeys(kId, expected_keys, false); | |
370 | |
371 std::vector<SerializedScriptValue> serialized_values; | |
372 | |
373 // {foo: "zoo", bar: null} | |
374 char16 data[] = {0x0353, 0x6f66, 0x536f, 0x7a03, 0x6f6f, 0x0353, 0x6162, | |
375 0x3072, 0x027b}; | |
376 serialized_values.push_back(SerializedScriptValue( | |
377 false, false, string16(data, arraysize(data)))); | |
378 | |
379 // null | |
380 serialized_values.push_back( | |
381 SerializedScriptValue(true, false, string16())); | |
382 | |
383 IndexedDBKeyPath key_path; | |
384 key_path.SetString(UTF8ToUTF16("PropertyNotAvailable")); | |
385 scoped_helper.CheckValuesForKeyPath(kId, serialized_values, key_path); | |
386 | |
387 // Call again with the Utility process in batch mode and with valid keys. | |
388 expected_keys.clear(); | |
389 IndexedDBKey value; | |
390 value.SetString(UTF8ToUTF16("zoo")); | |
391 expected_keys.push_back(value); | |
392 expected_keys.push_back(null_value); | |
393 scoped_helper.SetExpectedKeys(kId + 1, expected_keys, false); | |
394 key_path.SetString(UTF8ToUTF16("foo")); | |
395 scoped_helper.CheckValuesForKeyPath(kId + 1, serialized_values, key_path); | |
396 } | |
397 | |
398 IN_PROC_BROWSER_TEST_F(ContentBrowserTest, InjectIDBKey) { | |
399 // {foo: 'zoo'} | |
400 const char16 initial_data[] = {0x0353,0x6f66,0x536f,0x7a03,0x6f6f,0x017b}; | |
401 SerializedScriptValue value( | |
402 false, false, string16(initial_data, arraysize(initial_data))); | |
403 IndexedDBKey key; | |
404 key.SetString(UTF8ToUTF16("myNewKey")); | |
405 | |
406 ScopedIDBKeyPathHelper scoped_helper; | |
407 | |
408 // {foo: 'zoo', bar: 'myNewKey'} | |
409 const char16 expected_data[] = {0x01ff, 0x003f, 0x3f6f, 0x5301, 0x6603, | |
410 0x6f6f, 0x013f, 0x0353, 0x6f7a, 0x3f6f, | |
411 0x5301, 0x6203, 0x7261, 0x013f, 0x0853, | |
412 0x796d, 0x654e, 0x4b77, 0x7965, 0x027b}; | |
413 SerializedScriptValue expected_value( | |
414 false, false, string16(expected_data, arraysize(expected_data))); | |
415 scoped_helper.SetExpectedValue(expected_value); | |
416 IndexedDBKeyPath key_path; | |
417 key_path.SetString(UTF8ToUTF16("bar")); | |
418 scoped_helper.CheckInjectValue(key, value, key_path); | |
419 | |
420 // Should fail - can't apply properties to string value of key foo | |
421 const SerializedScriptValue failure_value; | |
422 scoped_helper.SetExpectedValue(failure_value); | |
423 key_path.SetString(UTF8ToUTF16("foo.bad.path")); | |
424 scoped_helper.CheckInjectValue(key, value, key_path); | |
425 | |
426 // {foo: 'zoo', bar: {baz: 'myNewKey'}} | |
427 const char16 expected_data2[] = {0x01ff, 0x003f, 0x3f6f, 0x5301, 0x6603, | |
428 0x6f6f, 0x013f, 0x0353, 0x6f7a, 0x3f6f, | |
429 0x5301, 0x6203, 0x7261, 0x013f, 0x3f6f, | |
430 0x5302, 0x6203, 0x7a61, 0x023f, 0x0853, | |
431 0x796d, 0x654e, 0x4b77, 0x7965, 0x017b, | |
432 0x027b}; | |
433 SerializedScriptValue expected_value2( | |
434 false, false, string16(expected_data2, arraysize(expected_data2))); | |
435 scoped_helper.SetExpectedValue(expected_value2); | |
436 key_path.SetString(UTF8ToUTF16("bar.baz")); | |
437 scoped_helper.CheckInjectValue(key, value, key_path); | |
438 } | |
439 | |
440 } // namespace content | |
OLD | NEW |