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

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

Issue 2784003002: [IndexedDB] Mojo testing harness. (Closed)
Patch Set: Restructured 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();
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 FlushIORunLoop();
181 // Cleanup on idb thread.
182 FlushIDBThreadRunLoop();
183 // Flush out replies.
184 FlushIORunLoop();
185 // We leak files if this doesn't return true.
186 ASSERT_TRUE(temp_dir_.Delete());
187 }
188
189 void SetUp() override {
190 ASSERT_TRUE(idb_task_runner_);
191 FactoryAssociatedRequest request =
192 ::mojo::MakeIsolatedRequest(&idb_mojo_factory_);
193 host_->AddBinding(std::move(request));
194 }
195
196 protected:
197 TestBrowserThreadBundle thread_bundle_;
198 TestBrowserContext browser_context_;
199
200 base::ScopedTempDir temp_dir_;
201 std::unique_ptr<base::Thread> idb_thread_;
202 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
203 scoped_refptr<base::SingleThreadTaskRunner> idb_task_runner_;
204 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
205 scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
206 scoped_refptr<MockQuotaManager> quota_manager_;
207 scoped_refptr<QuotaManagerProxy> quota_manager_proxy_;
208 scoped_refptr<IndexedDBContextImpl> context_impl_;
209 scoped_refptr<ChromeBlobStorageContext> blob_storage_;
210 std::unique_ptr<IndexedDBDispatcherHost, BrowserThread::DeleteOnIOThread>
211 host_;
212 FactoryAssociatedPtr idb_mojo_factory_;
213
214 DISALLOW_COPY_AND_ASSIGN(IndexedDBDispatcherHostTest);
215 };
216
217 TEST_F(IndexedDBDispatcherHostTest, CloseConnectionBeforeUpgrade) {
218 const int64_t kDBVersion = 1;
219 const int64_t kTransactionId = 1;
220
221 TestDatabaseConnection connection(url::Origin(GURL(kOrigin)),
222 base::UTF8ToUTF16(kDatabaseName),
223 kDBVersion, kTransactionId);
224 IndexedDBDatabaseMetadata metadata;
225 DatabaseAssociatedPtrInfo database_info;
226 base::RunLoop loop;
227 EXPECT_CALL(
228 *connection.open_callbacks,
229 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
230 IndexedDBDatabaseMetadata::NO_VERSION,
231 blink::kWebIDBDataLossNone, std::string(""), _))
232 .WillOnce(testing::DoAll(MoveArg<0>(&database_info),
233 testing::SaveArg<4>(&metadata),
234 RunClosure(loop.QuitClosure())));
235
236 connection.Open(idb_mojo_factory_.get());
237 idb_mojo_factory_.FlushForTesting();
238 loop.Run();
239
240 EXPECT_TRUE(database_info.is_valid());
241 EXPECT_EQ(connection.version, metadata.version);
242 EXPECT_EQ(connection.db_name, metadata.name);
243 }
244
245 TEST_F(IndexedDBDispatcherHostTest, CloseAfterUpgrade) {
246 const int64_t kDBVersion = 1;
247 const int64_t kTransactionId = 1;
248 const int64_t kObjectStoreId = 10;
249 const char kObjectStoreName[] = "os";
250
251 // Open connection.
252 TestDatabaseConnection connection(url::Origin(GURL(kOrigin)),
253 base::UTF8ToUTF16(kDatabaseName),
254 kDBVersion, kTransactionId);
255
256 IndexedDBDatabaseMetadata metadata;
257 DatabaseAssociatedPtrInfo database_info;
258 {
259 base::RunLoop loop;
260 EXPECT_CALL(
261 *connection.open_callbacks,
262 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
263 IndexedDBDatabaseMetadata::NO_VERSION,
264 blink::kWebIDBDataLossNone, std::string(""), _))
265 .WillOnce(testing::DoAll(MoveArg<0>(&database_info),
266 testing::SaveArg<4>(&metadata),
267 RunClosure(loop.QuitClosure())));
268
269 // Queue open request message.
270 connection.Open(idb_mojo_factory_.get());
271 idb_mojo_factory_.FlushForTesting();
272 loop.Run();
273 }
274
275 ASSERT_TRUE(database_info.is_valid());
276 EXPECT_EQ(connection.version, metadata.version);
277 EXPECT_EQ(connection.db_name, metadata.name);
278
279 connection.database.Bind(std::move(database_info));
280
281 {
282 ::testing::InSequence dummy;
283 base::RunLoop loop;
284 base::Closure quit_closure = base::BarrierClosure(2, loop.QuitClosure());
285 //
286 EXPECT_CALL(*connection.connection_callbacks, Complete(kTransactionId))
287 .Times(1)
288 .WillOnce(RunClosure(quit_closure));
289 EXPECT_CALL(
290 *connection.open_callbacks,
291 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(false), _))
292 .Times(1)
293 .WillOnce(RunClosure(quit_closure));
294
295 ASSERT_TRUE(connection.database.is_bound());
296 connection.database->CreateObjectStore(kTransactionId, kObjectStoreId,
297 base::UTF8ToUTF16(kObjectStoreName),
298 content::IndexedDBKeyPath(), false);
299 connection.database->Commit(kTransactionId);
300 connection.database.FlushForTesting();
301 loop.Run();
302 }
303 }
304
305 TEST_F(IndexedDBDispatcherHostTest, OpenNewConnectionWhileUpgrading) {
306 const int64_t kDBVersion = 1;
307 const int64_t kTransactionId = 1;
308 const int64_t kObjectStoreId = 10;
309 const char kObjectStoreName[] = "os";
310
311 // Open connection 1, and expect the upgrade needed.
312 TestDatabaseConnection connection1(url::Origin(GURL(kOrigin)),
313 base::UTF8ToUTF16(kDatabaseName),
314 kDBVersion, kTransactionId);
315 DatabaseAssociatedPtrInfo database_info1;
316 {
317 base::RunLoop loop;
318 IndexedDBDatabaseMetadata metadata;
319 EXPECT_CALL(
320 *connection1.open_callbacks,
321 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
322 IndexedDBDatabaseMetadata::NO_VERSION,
323 blink::kWebIDBDataLossNone, std::string(""), _))
324 .WillOnce(testing::DoAll(MoveArg<0>(&database_info1),
325 testing::SaveArg<4>(&metadata),
326 RunClosure(loop.QuitClosure())));
327
328 // Queue open request message.
329 connection1.Open(idb_mojo_factory_.get());
330 idb_mojo_factory_.FlushForTesting();
331 loop.Run();
332 }
333 connection1.database.Bind(std::move(database_info1));
334
335 // Open connection 2, but expect that we won't be called back.
336 DatabaseAssociatedPtrInfo database_info2;
337 IndexedDBDatabaseMetadata metadata2;
338 TestDatabaseConnection connection2(url::Origin(GURL(kOrigin)),
339 base::UTF8ToUTF16(kDatabaseName),
340 kDBVersion, 0);
341 connection2.Open(idb_mojo_factory_.get());
342 idb_mojo_factory_.FlushForTesting();
343 // If this was going to call us back, it would hit us here and we would fail
344 // our expectations.
345 FlushIDBThreadRunLoop();
346 FlushIORunLoop();
347
348 // Check that we're called in order and the second connection gets it's
349 // database.
350 {
351 ::testing::InSequence dummy;
352 base::RunLoop loop;
353 base::Closure quit_closure = base::BarrierClosure(3, loop.QuitClosure());
354 EXPECT_CALL(*connection1.connection_callbacks, Complete(kTransactionId))
355 .Times(1)
356 .WillOnce(RunClosure(quit_closure));
357 EXPECT_CALL(
358 *connection1.open_callbacks,
359 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(false), _))
360 .Times(1)
361 .WillOnce(RunClosure(quit_closure));
362 EXPECT_CALL(
363 *connection2.open_callbacks,
364 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(true), _))
365 .WillOnce(testing::DoAll(MoveArg<0>(&database_info2),
366 testing::SaveArg<1>(&metadata2),
367 RunClosure(quit_closure)));
368
369 // Create object store.
370 ASSERT_TRUE(connection1.database.is_bound());
371 connection1.database->CreateObjectStore(kTransactionId, kObjectStoreId,
372 base::UTF8ToUTF16(kObjectStoreName),
373 content::IndexedDBKeyPath(), false);
374 connection1.database->Commit(kTransactionId);
375 connection1.database.FlushForTesting();
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 idb_mojo_factory_.FlushForTesting();
411 loop.Run();
412 }
413
414 ASSERT_TRUE(database_info.is_valid());
415 EXPECT_EQ(connection.version, metadata.version);
416 EXPECT_EQ(connection.db_name, metadata.name);
417
418 connection.database.Bind(std::move(database_info));
419
420 {
421 ::testing::InSequence dummy;
422 base::RunLoop loop;
423 base::Closure quit_closure = base::BarrierClosure(3, loop.QuitClosure());
424
425 std::unique_ptr<MockMojoIndexedDBCallbacks> put_callbacks(
426 new StrictMock<MockMojoIndexedDBCallbacks>());
Reilly Grant (use Gerrit) 2017/05/15 21:24:33 auto put_callbacks = base::MakeUnique<StrictMock<M
dmurph 2017/05/16 20:43:25 Done.
427
428 EXPECT_CALL(*put_callbacks,
429 Error(blink::kWebIDBDatabaseExceptionUnknownError, _))
430 .Times(1)
431 .WillOnce(RunClosure(quit_closure));
432
433 EXPECT_CALL(
434 *connection.connection_callbacks,
435 Abort(kTransactionId, blink::kWebIDBDatabaseExceptionUnknownError, _))
436 .Times(1)
437 .WillOnce(RunClosure(quit_closure));
438
439 EXPECT_CALL(*connection.open_callbacks,
440 Error(blink::kWebIDBDatabaseExceptionAbortError, _))
441 .Times(1)
442 .WillOnce(RunClosure(quit_closure));
443
444 ASSERT_TRUE(connection.database.is_bound());
445 connection.database->CreateObjectStore(kTransactionId, kObjectStoreId,
446 base::UTF8ToUTF16(kObjectStoreName),
447 content::IndexedDBKeyPath(), false);
448 // Call Put with an invalid blob.
449 std::vector<::indexed_db::mojom::BlobInfoPtr> blobs;
450 blobs.push_back(::indexed_db::mojom::BlobInfo::New(
451 "fakeUUID", base::string16(), 100, nullptr));
452 connection.database->Put(kTransactionId, kObjectStoreId,
453 Value::New("hello", std::move(blobs)),
454 content::IndexedDBKey(base::UTF8ToUTF16("hello")),
455 blink::kWebIDBPutModeAddOnly,
456 std::vector<content::IndexedDBIndexKeys>(),
457 put_callbacks->CreateInterfacePtrAndBind());
458 connection.database->Commit(kTransactionId);
459 connection.database.FlushForTesting();
Reilly Grant (use Gerrit) 2017/05/15 21:24:33 Why is this necessary? |quit_closure| should be ha
dmurph 2017/05/16 20:43:25 Done.
460 loop.Run();
461 }
462 }
463
464 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/indexed_db/indexed_db_dispatcher_host.cc ('k') | content/browser/indexed_db/indexed_db_transaction.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698