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
19using WebKit::WebSerializedScriptValue;
20
21// Sanity test, check the function call directly outside the sandbox.
22TEST(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
62class 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.
190class 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
232IN_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
256IN_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
277IN_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
308IN_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