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. 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: 64 IDBKeyPathHelper() 65 : expected_id_(0), 66 utility_process_host_(NULL), 67 value_for_key_path_failed_(false) { 68 } 69 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 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 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 107 void SetExpectedValue(const SerializedScriptValue& expected_value) { 108 expected_value_ = expected_value; 109 } 110 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 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 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 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 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: 192 ScopedIDBKeyPathHelper() { 193 key_path_helper_ = new IDBKeyPathHelper(); 194 key_path_helper_->CreateUtilityProcess(); 195 ui_test_utils::RunMessageLoop(); 196 } 197 198 ~ScopedIDBKeyPathHelper() { 199 key_path_helper_->DestroyUtilityProcess(); 200 ui_test_utils::RunMessageLoop(); 201 } 202 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 208 void SetExpectedValue(const SerializedScriptValue& expected_value) { 209 key_path_helper_->SetExpectedValue(expected_value); 210 } 211 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 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 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 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 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 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