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

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

Issue 2784003002: [IndexedDB] Mojo testing harness. (Closed)
Patch Set: comments, removed thread flushing 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 }
163
164 void TearDown() override {
Ken Rockot(use gerrit already) 2017/05/16 23:12:47 Thanks, this seems better! One more change here t
165 host_.reset();
166 // In order for idb_thread_.Stop() to not cause thread/taskrunner checking
167 // errors, the handles must be deref'd before we join threads. This ensures
168 // classes that require destruction on the idb thread can be destructed
169 // correctly before scheduling on the the idb thread task runner turns into
170 // a no-op after thread join.
171 blob_storage_ = nullptr;
172 context_impl_ = nullptr;
173 quota_manager_proxy_ = nullptr;
174 quota_manager_ = nullptr;
175 special_storage_policy_ = nullptr;
176 request_context_getter_ = nullptr;
177 // This will run the idb task runner until idle, then join the threads.
178 idb_thread_->Stop();
179 // File are leaked if this doesn't return true.
180 ASSERT_TRUE(temp_dir_.Delete());
181 }
182
183 void SetUp() override {
184 ASSERT_TRUE(idb_task_runner_);
185 FactoryAssociatedRequest request =
186 ::mojo::MakeIsolatedRequest(&idb_mojo_factory_);
187 host_->AddBinding(std::move(request));
188 }
189
190 protected:
191 TestBrowserThreadBundle thread_bundle_;
192 TestBrowserContext browser_context_;
193
194 base::ScopedTempDir temp_dir_;
195 std::unique_ptr<base::Thread> idb_thread_;
196 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
197 scoped_refptr<base::SingleThreadTaskRunner> idb_task_runner_;
198 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
199 scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
200 scoped_refptr<MockQuotaManager> quota_manager_;
201 scoped_refptr<QuotaManagerProxy> quota_manager_proxy_;
202 scoped_refptr<IndexedDBContextImpl> context_impl_;
203 scoped_refptr<ChromeBlobStorageContext> blob_storage_;
204 std::unique_ptr<IndexedDBDispatcherHost, BrowserThread::DeleteOnIOThread>
205 host_;
206 FactoryAssociatedPtr idb_mojo_factory_;
207
208 DISALLOW_COPY_AND_ASSIGN(IndexedDBDispatcherHostTest);
209 };
210
211 TEST_F(IndexedDBDispatcherHostTest, CloseConnectionBeforeUpgrade) {
212 const int64_t kDBVersion = 1;
213 const int64_t kTransactionId = 1;
214
215 TestDatabaseConnection connection(url::Origin(GURL(kOrigin)),
216 base::UTF8ToUTF16(kDatabaseName),
217 kDBVersion, kTransactionId);
218 IndexedDBDatabaseMetadata metadata;
219 DatabaseAssociatedPtrInfo database_info;
220 base::RunLoop loop;
221 EXPECT_CALL(
222 *connection.open_callbacks,
223 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
224 IndexedDBDatabaseMetadata::NO_VERSION,
225 blink::kWebIDBDataLossNone, std::string(""), _))
226 .WillOnce(testing::DoAll(MoveArg<0>(&database_info),
227 testing::SaveArg<4>(&metadata),
228 RunClosure(loop.QuitClosure())));
229
230 connection.Open(idb_mojo_factory_.get());
231 loop.Run();
232
233 EXPECT_TRUE(database_info.is_valid());
234 EXPECT_EQ(connection.version, metadata.version);
235 EXPECT_EQ(connection.db_name, metadata.name);
236 }
237
238 TEST_F(IndexedDBDispatcherHostTest, CloseAfterUpgrade) {
239 const int64_t kDBVersion = 1;
240 const int64_t kTransactionId = 1;
241 const int64_t kObjectStoreId = 10;
242 const char kObjectStoreName[] = "os";
243
244 // Open connection.
245 TestDatabaseConnection connection(url::Origin(GURL(kOrigin)),
246 base::UTF8ToUTF16(kDatabaseName),
247 kDBVersion, kTransactionId);
248
249 IndexedDBDatabaseMetadata metadata;
250 DatabaseAssociatedPtrInfo database_info;
251 {
252 base::RunLoop loop;
253 EXPECT_CALL(
254 *connection.open_callbacks,
255 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
256 IndexedDBDatabaseMetadata::NO_VERSION,
257 blink::kWebIDBDataLossNone, std::string(""), _))
258 .WillOnce(testing::DoAll(MoveArg<0>(&database_info),
259 testing::SaveArg<4>(&metadata),
260 RunClosure(loop.QuitClosure())));
261
262 // Queue open request message.
263 connection.Open(idb_mojo_factory_.get());
264 loop.Run();
265 }
266
267 ASSERT_TRUE(database_info.is_valid());
268 EXPECT_EQ(connection.version, metadata.version);
269 EXPECT_EQ(connection.db_name, metadata.name);
270
271 connection.database.Bind(std::move(database_info));
272
273 {
274 ::testing::InSequence dummy;
275 base::RunLoop loop;
276 base::Closure quit_closure = base::BarrierClosure(2, loop.QuitClosure());
277 EXPECT_CALL(*connection.connection_callbacks, Complete(kTransactionId))
278 .Times(1)
279 .WillOnce(RunClosure(quit_closure));
280 EXPECT_CALL(
281 *connection.open_callbacks,
282 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(false), _))
283 .Times(1)
284 .WillOnce(RunClosure(quit_closure));
285
286 ASSERT_TRUE(connection.database.is_bound());
287 connection.database->CreateObjectStore(kTransactionId, kObjectStoreId,
288 base::UTF8ToUTF16(kObjectStoreName),
289 content::IndexedDBKeyPath(), false);
290 connection.database->Commit(kTransactionId);
291 loop.Run();
292 }
293 }
294
295 TEST_F(IndexedDBDispatcherHostTest, OpenNewConnectionWhileUpgrading) {
296 const int64_t kDBVersion = 1;
297 const int64_t kTransactionId = 1;
298 const int64_t kObjectStoreId = 10;
299 const char kObjectStoreName[] = "os";
300
301 // Open connection 1, and expect the upgrade needed.
302 TestDatabaseConnection connection1(url::Origin(GURL(kOrigin)),
303 base::UTF8ToUTF16(kDatabaseName),
304 kDBVersion, kTransactionId);
305 DatabaseAssociatedPtrInfo database_info1;
306 {
307 base::RunLoop loop;
308 IndexedDBDatabaseMetadata metadata;
309 EXPECT_CALL(
310 *connection1.open_callbacks,
311 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
312 IndexedDBDatabaseMetadata::NO_VERSION,
313 blink::kWebIDBDataLossNone, std::string(""), _))
314 .WillOnce(testing::DoAll(MoveArg<0>(&database_info1),
315 testing::SaveArg<4>(&metadata),
316 RunClosure(loop.QuitClosure())));
317
318 // Queue open request message.
319 connection1.Open(idb_mojo_factory_.get());
320 loop.Run();
321 }
322 connection1.database.Bind(std::move(database_info1));
323
324 // Open connection 2, but expect that we won't be called back.
325 DatabaseAssociatedPtrInfo database_info2;
326 IndexedDBDatabaseMetadata metadata2;
327 TestDatabaseConnection connection2(url::Origin(GURL(kOrigin)),
328 base::UTF8ToUTF16(kDatabaseName),
329 kDBVersion, 0);
330 connection2.Open(idb_mojo_factory_.get());
331
332 // Check that we're called in order and the second connection gets it's
333 // database after the first connection completes.
334 {
335 ::testing::InSequence dummy;
336 base::RunLoop loop;
337 base::Closure quit_closure = base::BarrierClosure(3, loop.QuitClosure());
338 EXPECT_CALL(*connection1.connection_callbacks, Complete(kTransactionId))
339 .Times(1)
340 .WillOnce(RunClosure(quit_closure));
341 EXPECT_CALL(
342 *connection1.open_callbacks,
343 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(false), _))
344 .Times(1)
345 .WillOnce(RunClosure(quit_closure));
346 EXPECT_CALL(
347 *connection2.open_callbacks,
348 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(true), _))
349 .WillOnce(testing::DoAll(MoveArg<0>(&database_info2),
350 testing::SaveArg<1>(&metadata2),
351 RunClosure(quit_closure)));
352
353 // Create object store.
354 ASSERT_TRUE(connection1.database.is_bound());
355 connection1.database->CreateObjectStore(kTransactionId, kObjectStoreId,
356 base::UTF8ToUTF16(kObjectStoreName),
357 content::IndexedDBKeyPath(), false);
358 connection1.database->Commit(kTransactionId);
359 loop.Run();
360 }
361
362 EXPECT_TRUE(database_info2.is_valid());
363 EXPECT_EQ(connection2.version, metadata2.version);
364 EXPECT_EQ(connection2.db_name, metadata2.name);
365 }
366
367 TEST_F(IndexedDBDispatcherHostTest, PutWithInvalidBlob) {
368 const int64_t kDBVersion = 1;
369 const int64_t kTransactionId = 1;
370 const int64_t kObjectStoreId = 10;
371 const char kObjectStoreName[] = "os";
372
373 // Open connection.
374 TestDatabaseConnection connection(url::Origin(GURL(kOrigin)),
375 base::UTF8ToUTF16(kDatabaseName),
376 kDBVersion, kTransactionId);
377
378 IndexedDBDatabaseMetadata metadata;
379 DatabaseAssociatedPtrInfo database_info;
380 {
381 base::RunLoop loop;
382 EXPECT_CALL(
383 *connection.open_callbacks,
384 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
385 IndexedDBDatabaseMetadata::NO_VERSION,
386 blink::kWebIDBDataLossNone, std::string(""), _))
387 .WillOnce(testing::DoAll(MoveArg<0>(&database_info),
388 testing::SaveArg<4>(&metadata),
389 RunClosure(loop.QuitClosure())));
390
391 // Queue open request message.
392 connection.Open(idb_mojo_factory_.get());
393 loop.Run();
394 }
395
396 ASSERT_TRUE(database_info.is_valid());
397 EXPECT_EQ(connection.version, metadata.version);
398 EXPECT_EQ(connection.db_name, metadata.name);
399
400 connection.database.Bind(std::move(database_info));
401
402 {
403 ::testing::InSequence dummy;
404 base::RunLoop loop;
405 base::Closure quit_closure = base::BarrierClosure(3, loop.QuitClosure());
406
407 auto put_callbacks =
408 base::MakeUnique<StrictMock<MockMojoIndexedDBCallbacks>>();
409
410 EXPECT_CALL(*put_callbacks,
411 Error(blink::kWebIDBDatabaseExceptionUnknownError, _))
412 .Times(1)
413 .WillOnce(RunClosure(quit_closure));
414
415 EXPECT_CALL(
416 *connection.connection_callbacks,
417 Abort(kTransactionId, blink::kWebIDBDatabaseExceptionUnknownError, _))
418 .Times(1)
419 .WillOnce(RunClosure(quit_closure));
420
421 EXPECT_CALL(*connection.open_callbacks,
422 Error(blink::kWebIDBDatabaseExceptionAbortError, _))
423 .Times(1)
424 .WillOnce(RunClosure(quit_closure));
425
426 ASSERT_TRUE(connection.database.is_bound());
427 connection.database->CreateObjectStore(kTransactionId, kObjectStoreId,
428 base::UTF8ToUTF16(kObjectStoreName),
429 content::IndexedDBKeyPath(), false);
430 // Call Put with an invalid blob.
431 std::vector<::indexed_db::mojom::BlobInfoPtr> blobs;
432 blobs.push_back(::indexed_db::mojom::BlobInfo::New(
433 "fakeUUID", base::string16(), 100, nullptr));
434 connection.database->Put(kTransactionId, kObjectStoreId,
435 Value::New("hello", std::move(blobs)),
436 content::IndexedDBKey(base::UTF8ToUTF16("hello")),
437 blink::kWebIDBPutModeAddOnly,
438 std::vector<content::IndexedDBIndexKeys>(),
439 put_callbacks->CreateInterfacePtrAndBind());
440 connection.database->Commit(kTransactionId);
441 loop.Run();
442 }
443 }
444
445 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/indexed_db/indexed_db_dispatcher_host.h ('k') | content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698