Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(230)

Side by Side Diff: content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc

Issue 2784003002: [IndexedDB] Mojo testing harness. (Closed)
Patch Set: comments Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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 "content/browser/indexed_db/indexed_db_dispatcher_host.h"
6
7 #include "base/barrier_closure.h"
8 #include "base/callback.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/run_loop.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/strings/utf_offset_string_conversions.h"
15 #include "base/test/test_simple_task_runner.h"
16 #include "base/threading/thread.h"
17 #include "content/browser/browser_thread_impl.h"
18 #include "content/browser/indexed_db/indexed_db_callbacks.h"
19 #include "content/browser/indexed_db/indexed_db_context_impl.h"
20 #include "content/browser/indexed_db/indexed_db_database_callbacks.h"
21 #include "content/browser/indexed_db/indexed_db_factory.h"
22 #include "content/browser/indexed_db/indexed_db_pending_connection.h"
23 #include "content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h"
24 #include "content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h"
25 #include "content/common/indexed_db/indexed_db.mojom.h"
26 #include "content/public/test/test_browser_context.h"
27 #include "content/public/test/test_browser_thread_bundle.h"
28 #include "mojo/public/cpp/bindings/associated_interface_ptr.h"
29 #include "mojo/public/cpp/bindings/strong_associated_binding.h"
30 #include "net/url_request/url_request_test_util.h"
31 #include "storage/browser/test/mock_quota_manager.h"
32 #include "storage/browser/test/mock_quota_manager_proxy.h"
33 #include "storage/browser/test/mock_special_storage_policy.h"
34 #include "testing/gmock/include/gmock/gmock.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseExc eption.h"
37 #include "url/origin.h"
38
39 using indexed_db::mojom::Callbacks;
40 using indexed_db::mojom::CallbacksAssociatedPtrInfo;
41 using indexed_db::mojom::DatabaseAssociatedPtr;
42 using indexed_db::mojom::DatabaseAssociatedPtrInfo;
43 using indexed_db::mojom::DatabaseAssociatedRequest;
44 using indexed_db::mojom::DatabaseCallbacks;
45 using indexed_db::mojom::DatabaseCallbacksAssociatedPtrInfo;
46 using indexed_db::mojom::Factory;
47 using indexed_db::mojom::FactoryAssociatedPtr;
48 using indexed_db::mojom::FactoryAssociatedRequest;
49 using indexed_db::mojom::KeyPath;
50 using indexed_db::mojom::Value;
51 using indexed_db::mojom::ValuePtr;
52 using mojo::StrongAssociatedBindingPtr;
53 using testing::_;
54 using testing::StrictMock;
55
56 namespace content {
57 namespace {
58
59 ACTION_TEMPLATE(MoveArg,
60 HAS_1_TEMPLATE_PARAMS(int, k),
61 AND_1_VALUE_PARAMS(out)) {
62 *out = std::move(*::testing::get<k>(args));
63 };
64
65 ACTION_P(RunClosure, closure) {
66 closure.Run();
67 }
68
69 MATCHER_P(IsAssociatedInterfacePtrInfoValid,
70 tf,
71 std::string(negation ? "isn't" : "is") + " " +
72 std::string(tf ? "valid" : "invalid")) {
73 return tf == arg->is_valid();
74 }
75
76 MATCHER_P(MatchesIDBKey, key, "") {
77 return arg.Equals(key);
78 }
79
80 typedef void (base::Closure::*ClosureRunFcn)() const &;
81
82 static const char kDatabaseName[] = "db";
83 static const char kOrigin[] = "https://www.example.com";
84 static const int kFakeProcessId = 2;
85 static const int64_t kTemporaryQuota = 50 * 1024 * 1024;
86 static const int64_t kPersistantQuota = 50 * 1024 * 1024;
87
88 base::FilePath CreateAndReturnTempDir(base::ScopedTempDir* temp_dir) {
89 CHECK(temp_dir->CreateUniqueTempDir());
90 return temp_dir->GetPath();
91 }
92
93 // Stores data specific to a connection.
94 struct TestDatabaseConnection {
95 TestDatabaseConnection(url::Origin origin,
96 base::string16 db_name,
97 int64_t version,
98 int64_t upgrade_txn_id)
99 : origin(std::move(origin)),
100 db_name(std::move(db_name)),
101 version(version),
102 upgrade_txn_id(upgrade_txn_id),
103 open_callbacks(new StrictMock<MockMojoIndexedDBCallbacks>()),
104 connection_callbacks(
105 new StrictMock<MockMojoIndexedDBDatabaseCallbacks>()){};
106 ~TestDatabaseConnection() {}
107
108 void Open(Factory* factory) {
109 factory->Open(open_callbacks->CreateInterfacePtrAndBind(),
110 connection_callbacks->CreateInterfacePtrAndBind(), origin,
111 db_name, version, upgrade_txn_id);
112 }
113
114 url::Origin origin;
115 base::string16 db_name;
116 int64_t version;
117 int64_t upgrade_txn_id;
118
119 DatabaseAssociatedPtr database;
120
121 std::unique_ptr<MockMojoIndexedDBCallbacks> open_callbacks;
122 std::unique_ptr<MockMojoIndexedDBDatabaseCallbacks> connection_callbacks;
123
124 private:
125 DISALLOW_COPY_AND_ASSIGN(TestDatabaseConnection);
126 };
127
128 } // namespace
129
130 class IndexedDBDispatcherHostTest : public testing::Test {
131 public:
132 IndexedDBDispatcherHostTest()
133 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
134 idb_thread_(new base::Thread("IndexedDB")),
135 io_task_runner_(
136 BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)),
137 idb_task_runner_(idb_thread_->Start() ? idb_thread_->task_runner()
138 : nullptr),
139 request_context_getter_(
140 new net::TestURLRequestContextGetter(io_task_runner_)),
141 special_storage_policy_(new MockSpecialStoragePolicy()),
142 quota_manager_(new MockQuotaManager(false,
143 browser_context_.GetPath(),
144 io_task_runner_,
145 idb_task_runner_,
146 special_storage_policy_)),
147 quota_manager_proxy_(quota_manager_->proxy()),
148 context_impl_(
149 new IndexedDBContextImpl(CreateAndReturnTempDir(&temp_dir_),
150 special_storage_policy_.get(),
151 quota_manager_proxy_.get(),
152 idb_task_runner_.get())),
153 blob_storage_(ChromeBlobStorageContext::GetFor(&browser_context_)),
154 host_(new IndexedDBDispatcherHost(kFakeProcessId,
155 request_context_getter_.get(),
156 context_impl_.get(),
157 blob_storage_.get())) {
158 quota_manager_->SetQuota(GURL(kOrigin), storage::kStorageTypePersistent,
159 kTemporaryQuota);
160 quota_manager_->SetQuota(GURL(kOrigin), storage::kStorageTypeTemporary,
161 kPersistantQuota);
162 FlushIORunLoop();
Ken Rockot(use gerrit already) 2017/05/16 21:06:32 This is not really a better testing strategy than
dmurph 2017/05/16 23:06:43 My main concern here is shutdown. If we have hops
163 }
164
165 void FlushIORunLoop() {
166 base::RunLoop loop;
167 io_task_runner_->PostTask(FROM_HERE, loop.QuitClosure());
168 loop.Run();
169 }
170
171 void FlushIDBThreadRunLoop() {
172 base::RunLoop loop;
173 idb_task_runner_->PostTaskAndReply(FROM_HERE, base::Bind(base::DoNothing),
174 loop.QuitClosure());
175 loop.Run();
176 }
177
178 void TearDown() override {
179 host_.reset();
180 // NOTE: If this test is flaky due to timeout / deadlock, then we need to be
181 // 1. Destroying all of the objects below that have a ref to indexeddb (esp
182 // the quota manager).
183 // 2. Call Stop() on the idb_thread_.
184 // 3. Finish cleanup, delete temp dir.
185 FlushIORunLoop();
Ken Rockot(use gerrit already) 2017/05/16 21:06:32 This sequence of "flush" operations is a gigantic
dmurph 2017/05/16 23:06:43 I re-did this to deref all objects before joining
186 // Cleanup on idb thread.
187 FlushIDBThreadRunLoop();
188 // Flush out replies.
189 FlushIORunLoop();
190 // We leak files if this doesn't return true.
191 ASSERT_TRUE(temp_dir_.Delete());
192 }
193
194 void SetUp() override {
195 ASSERT_TRUE(idb_task_runner_);
196 FactoryAssociatedRequest request =
197 ::mojo::MakeIsolatedRequest(&idb_mojo_factory_);
198 host_->AddBinding(std::move(request));
199 }
200
201 protected:
202 TestBrowserThreadBundle thread_bundle_;
203 TestBrowserContext browser_context_;
204
205 base::ScopedTempDir temp_dir_;
206 std::unique_ptr<base::Thread> idb_thread_;
207 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
208 scoped_refptr<base::SingleThreadTaskRunner> idb_task_runner_;
209 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
210 scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
211 scoped_refptr<MockQuotaManager> quota_manager_;
212 scoped_refptr<QuotaManagerProxy> quota_manager_proxy_;
213 scoped_refptr<IndexedDBContextImpl> context_impl_;
214 scoped_refptr<ChromeBlobStorageContext> blob_storage_;
215 std::unique_ptr<IndexedDBDispatcherHost, BrowserThread::DeleteOnIOThread>
216 host_;
217 FactoryAssociatedPtr idb_mojo_factory_;
218
219 DISALLOW_COPY_AND_ASSIGN(IndexedDBDispatcherHostTest);
220 };
221
222 TEST_F(IndexedDBDispatcherHostTest, CloseConnectionBeforeUpgrade) {
223 const int64_t kDBVersion = 1;
224 const int64_t kTransactionId = 1;
225
226 TestDatabaseConnection connection(url::Origin(GURL(kOrigin)),
227 base::UTF8ToUTF16(kDatabaseName),
228 kDBVersion, kTransactionId);
229 IndexedDBDatabaseMetadata metadata;
230 DatabaseAssociatedPtrInfo database_info;
231 base::RunLoop loop;
232 EXPECT_CALL(
233 *connection.open_callbacks,
234 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
235 IndexedDBDatabaseMetadata::NO_VERSION,
236 blink::kWebIDBDataLossNone, std::string(""), _))
237 .WillOnce(testing::DoAll(MoveArg<0>(&database_info),
238 testing::SaveArg<4>(&metadata),
239 RunClosure(loop.QuitClosure())));
240
241 connection.Open(idb_mojo_factory_.get());
242 loop.Run();
243
244 EXPECT_TRUE(database_info.is_valid());
245 EXPECT_EQ(connection.version, metadata.version);
246 EXPECT_EQ(connection.db_name, metadata.name);
247 }
248
249 TEST_F(IndexedDBDispatcherHostTest, CloseAfterUpgrade) {
250 const int64_t kDBVersion = 1;
251 const int64_t kTransactionId = 1;
252 const int64_t kObjectStoreId = 10;
253 const char kObjectStoreName[] = "os";
254
255 // Open connection.
256 TestDatabaseConnection connection(url::Origin(GURL(kOrigin)),
257 base::UTF8ToUTF16(kDatabaseName),
258 kDBVersion, kTransactionId);
259
260 IndexedDBDatabaseMetadata metadata;
261 DatabaseAssociatedPtrInfo database_info;
262 {
263 base::RunLoop loop;
264 EXPECT_CALL(
265 *connection.open_callbacks,
266 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
267 IndexedDBDatabaseMetadata::NO_VERSION,
268 blink::kWebIDBDataLossNone, std::string(""), _))
269 .WillOnce(testing::DoAll(MoveArg<0>(&database_info),
270 testing::SaveArg<4>(&metadata),
271 RunClosure(loop.QuitClosure())));
272
273 // Queue open request message.
274 connection.Open(idb_mojo_factory_.get());
275 loop.Run();
276 }
277
278 ASSERT_TRUE(database_info.is_valid());
279 EXPECT_EQ(connection.version, metadata.version);
280 EXPECT_EQ(connection.db_name, metadata.name);
281
282 connection.database.Bind(std::move(database_info));
283
284 {
285 ::testing::InSequence dummy;
286 base::RunLoop loop;
287 base::Closure quit_closure = base::BarrierClosure(2, loop.QuitClosure());
288 //
Reilly Grant (use Gerrit) 2017/05/16 20:55:13 extra comment?
dmurph 2017/05/16 23:06:43 Done.
289 EXPECT_CALL(*connection.connection_callbacks, Complete(kTransactionId))
290 .Times(1)
291 .WillOnce(RunClosure(quit_closure));
292 EXPECT_CALL(
293 *connection.open_callbacks,
294 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(false), _))
295 .Times(1)
296 .WillOnce(RunClosure(quit_closure));
297
298 ASSERT_TRUE(connection.database.is_bound());
299 connection.database->CreateObjectStore(kTransactionId, kObjectStoreId,
300 base::UTF8ToUTF16(kObjectStoreName),
301 content::IndexedDBKeyPath(), false);
302 connection.database->Commit(kTransactionId);
303 loop.Run();
304 }
305 }
306
307 TEST_F(IndexedDBDispatcherHostTest, OpenNewConnectionWhileUpgrading) {
308 const int64_t kDBVersion = 1;
309 const int64_t kTransactionId = 1;
310 const int64_t kObjectStoreId = 10;
311 const char kObjectStoreName[] = "os";
312
313 // Open connection 1, and expect the upgrade needed.
314 TestDatabaseConnection connection1(url::Origin(GURL(kOrigin)),
315 base::UTF8ToUTF16(kDatabaseName),
316 kDBVersion, kTransactionId);
317 DatabaseAssociatedPtrInfo database_info1;
318 {
319 base::RunLoop loop;
320 IndexedDBDatabaseMetadata metadata;
321 EXPECT_CALL(
322 *connection1.open_callbacks,
323 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
324 IndexedDBDatabaseMetadata::NO_VERSION,
325 blink::kWebIDBDataLossNone, std::string(""), _))
326 .WillOnce(testing::DoAll(MoveArg<0>(&database_info1),
327 testing::SaveArg<4>(&metadata),
328 RunClosure(loop.QuitClosure())));
329
330 // Queue open request message.
331 connection1.Open(idb_mojo_factory_.get());
332 loop.Run();
333 }
334 connection1.database.Bind(std::move(database_info1));
335
336 // Open connection 2, but expect that we won't be called back.
337 DatabaseAssociatedPtrInfo database_info2;
338 IndexedDBDatabaseMetadata metadata2;
339 TestDatabaseConnection connection2(url::Origin(GURL(kOrigin)),
340 base::UTF8ToUTF16(kDatabaseName),
341 kDBVersion, 0);
342 connection2.Open(idb_mojo_factory_.get());
343 idb_mojo_factory_.FlushForTesting();
344 // If this was going to call us back, it would hit us here and we would fail
345 // our expectations.
346 FlushIDBThreadRunLoop();
347 FlushIORunLoop();
Reilly Grant (use Gerrit) 2017/05/16 20:55:13 I'm not convinced all this flushing is necessary.
dmurph 2017/05/16 23:06:44 You're right - the InSequence constraint should ha
348
349 // Check that we're called in order and the second connection gets it's
350 // database.
351 {
352 ::testing::InSequence dummy;
353 base::RunLoop loop;
354 base::Closure quit_closure = base::BarrierClosure(3, loop.QuitClosure());
355 EXPECT_CALL(*connection1.connection_callbacks, Complete(kTransactionId))
356 .Times(1)
357 .WillOnce(RunClosure(quit_closure));
358 EXPECT_CALL(
359 *connection1.open_callbacks,
360 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(false), _))
361 .Times(1)
362 .WillOnce(RunClosure(quit_closure));
363 EXPECT_CALL(
364 *connection2.open_callbacks,
365 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(true), _))
366 .WillOnce(testing::DoAll(MoveArg<0>(&database_info2),
367 testing::SaveArg<1>(&metadata2),
368 RunClosure(quit_closure)));
369
370 // Create object store.
371 ASSERT_TRUE(connection1.database.is_bound());
372 connection1.database->CreateObjectStore(kTransactionId, kObjectStoreId,
373 base::UTF8ToUTF16(kObjectStoreName),
374 content::IndexedDBKeyPath(), false);
375 connection1.database->Commit(kTransactionId);
376 loop.Run();
377 }
378
379 EXPECT_TRUE(database_info2.is_valid());
380 EXPECT_EQ(connection2.version, metadata2.version);
381 EXPECT_EQ(connection2.db_name, metadata2.name);
382 }
383
384 TEST_F(IndexedDBDispatcherHostTest, PutWithInvalidBlob) {
385 const int64_t kDBVersion = 1;
386 const int64_t kTransactionId = 1;
387 const int64_t kObjectStoreId = 10;
388 const char kObjectStoreName[] = "os";
389
390 // Open connection.
391 TestDatabaseConnection connection(url::Origin(GURL(kOrigin)),
392 base::UTF8ToUTF16(kDatabaseName),
393 kDBVersion, kTransactionId);
394
395 IndexedDBDatabaseMetadata metadata;
396 DatabaseAssociatedPtrInfo database_info;
397 {
398 base::RunLoop loop;
399 EXPECT_CALL(
400 *connection.open_callbacks,
401 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
402 IndexedDBDatabaseMetadata::NO_VERSION,
403 blink::kWebIDBDataLossNone, std::string(""), _))
404 .WillOnce(testing::DoAll(MoveArg<0>(&database_info),
405 testing::SaveArg<4>(&metadata),
406 RunClosure(loop.QuitClosure())));
407
408 // Queue open request message.
409 connection.Open(idb_mojo_factory_.get());
410 loop.Run();
411 }
412
413 ASSERT_TRUE(database_info.is_valid());
414 EXPECT_EQ(connection.version, metadata.version);
415 EXPECT_EQ(connection.db_name, metadata.name);
416
417 connection.database.Bind(std::move(database_info));
418
419 {
420 ::testing::InSequence dummy;
421 base::RunLoop loop;
422 base::Closure quit_closure = base::BarrierClosure(3, loop.QuitClosure());
423
424 auto put_callbacks =
425 base::MakeUnique<StrictMock<MockMojoIndexedDBCallbacks>>();
426
427 EXPECT_CALL(*put_callbacks,
428 Error(blink::kWebIDBDatabaseExceptionUnknownError, _))
429 .Times(1)
430 .WillOnce(RunClosure(quit_closure));
431
432 EXPECT_CALL(
433 *connection.connection_callbacks,
434 Abort(kTransactionId, blink::kWebIDBDatabaseExceptionUnknownError, _))
435 .Times(1)
436 .WillOnce(RunClosure(quit_closure));
437
438 EXPECT_CALL(*connection.open_callbacks,
439 Error(blink::kWebIDBDatabaseExceptionAbortError, _))
440 .Times(1)
441 .WillOnce(RunClosure(quit_closure));
442
443 ASSERT_TRUE(connection.database.is_bound());
444 connection.database->CreateObjectStore(kTransactionId, kObjectStoreId,
445 base::UTF8ToUTF16(kObjectStoreName),
446 content::IndexedDBKeyPath(), false);
447 // Call Put with an invalid blob.
448 std::vector<::indexed_db::mojom::BlobInfoPtr> blobs;
449 blobs.push_back(::indexed_db::mojom::BlobInfo::New(
450 "fakeUUID", base::string16(), 100, nullptr));
451 connection.database->Put(kTransactionId, kObjectStoreId,
452 Value::New("hello", std::move(blobs)),
453 content::IndexedDBKey(base::UTF8ToUTF16("hello")),
454 blink::kWebIDBPutModeAddOnly,
455 std::vector<content::IndexedDBIndexKeys>(),
456 put_callbacks->CreateInterfacePtrAndBind());
457 connection.database->Commit(kTransactionId);
458 loop.Run();
459 }
460 }
461
462 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698