| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <cerrno> |
| |
| #include "base/files/file.h" |
| #include "base/files/file_path.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "content/browser/indexed_db/indexed_db_backing_store.h" |
| #include "content/browser/indexed_db/leveldb/leveldb_database.h" |
| #include "content/browser/indexed_db/leveldb/mock_leveldb_factory.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/leveldatabase/env_chromium.h" |
| |
| using base::StringPiece; |
| using content::IndexedDBBackingStore; |
| using content::LevelDBComparator; |
| using content::LevelDBDatabase; |
| using content::LevelDBFactory; |
| using content::LevelDBSnapshot; |
| using testing::_; |
| using testing::Exactly; |
| using testing::Invoke; |
| |
| namespace base { |
| class TaskRunner; |
| } |
| |
| namespace content { |
| class IndexedDBFactory; |
| } |
| |
| namespace net { |
| class URLRequestContext; |
| } |
| |
| namespace { |
| |
| class BustedLevelDBDatabase : public LevelDBDatabase { |
| public: |
| BustedLevelDBDatabase() {} |
| static scoped_ptr<LevelDBDatabase> Open( |
| const base::FilePath& file_name, |
| const LevelDBComparator* /*comparator*/) { |
| return scoped_ptr<LevelDBDatabase>(new BustedLevelDBDatabase); |
| } |
| virtual leveldb::Status Get(const base::StringPiece& key, |
| std::string* value, |
| bool* found, |
| const LevelDBSnapshot* = 0) OVERRIDE { |
| return leveldb::Status::IOError("It's busted!"); |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(BustedLevelDBDatabase); |
| }; |
| |
| class BustedLevelDBFactory : public LevelDBFactory { |
| public: |
| virtual leveldb::Status OpenLevelDB( |
| const base::FilePath& file_name, |
| const LevelDBComparator* comparator, |
| scoped_ptr<LevelDBDatabase>* db, |
| bool* is_disk_full = 0) OVERRIDE { |
| if (open_error_.ok()) |
| *db = BustedLevelDBDatabase::Open(file_name, comparator); |
| return open_error_; |
| } |
| virtual leveldb::Status DestroyLevelDB( |
| const base::FilePath& file_name) OVERRIDE { |
| return leveldb::Status::IOError("error"); |
| } |
| void SetOpenError(const leveldb::Status& open_error) { |
| open_error_ = open_error; |
| } |
| |
| private: |
| leveldb::Status open_error_; |
| }; |
| |
| TEST(IndexedDBIOErrorTest, CleanUpTest) { |
| content::IndexedDBFactory* factory = NULL; |
| const GURL origin("http://localhost:81"); |
| base::ScopedTempDir temp_directory; |
| ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| const base::FilePath path = temp_directory.path(); |
| net::URLRequestContext* request_context = NULL; |
| |
| BustedLevelDBFactory busted_factory; |
| content::MockLevelDBFactory mock_leveldb_factory; |
| ON_CALL(mock_leveldb_factory, OpenLevelDB(_, _, _, _)).WillByDefault( |
| Invoke(&busted_factory, &BustedLevelDBFactory::OpenLevelDB)); |
| ON_CALL(mock_leveldb_factory, DestroyLevelDB(_)).WillByDefault( |
| Invoke(&busted_factory, &BustedLevelDBFactory::DestroyLevelDB)); |
| |
| EXPECT_CALL(mock_leveldb_factory, OpenLevelDB(_, _, _, _)).Times(Exactly(1)); |
| EXPECT_CALL(mock_leveldb_factory, DestroyLevelDB(_)).Times(Exactly(1)); |
| blink::WebIDBDataLoss data_loss = blink::WebIDBDataLossNone; |
| std::string data_loss_message; |
| bool disk_full = false; |
| base::SequencedTaskRunner* task_runner = NULL; |
| bool clean_journal = false; |
| leveldb::Status s; |
| scoped_refptr<IndexedDBBackingStore> backing_store = |
| IndexedDBBackingStore::Open(factory, |
| origin, |
| path, |
| request_context, |
| &data_loss, |
| &data_loss_message, |
| &disk_full, |
| &mock_leveldb_factory, |
| task_runner, |
| clean_journal, |
| &s); |
| } |
| |
| TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) { |
| content::IndexedDBFactory* factory = NULL; |
| const GURL origin("http://localhost:81"); |
| net::URLRequestContext* request_context = NULL; |
| base::ScopedTempDir temp_directory; |
| ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| const base::FilePath path = temp_directory.path(); |
| blink::WebIDBDataLoss data_loss = |
| blink::WebIDBDataLossNone; |
| std::string data_loss_reason; |
| bool disk_full = false; |
| base::SequencedTaskRunner* task_runner = NULL; |
| bool clean_journal = false; |
| leveldb::Status s; |
| |
| BustedLevelDBFactory busted_factory; |
| content::MockLevelDBFactory mock_leveldb_factory; |
| ON_CALL(mock_leveldb_factory, OpenLevelDB(_, _, _, _)).WillByDefault( |
| Invoke(&busted_factory, &BustedLevelDBFactory::OpenLevelDB)); |
| ON_CALL(mock_leveldb_factory, DestroyLevelDB(_)).WillByDefault( |
| Invoke(&busted_factory, &BustedLevelDBFactory::DestroyLevelDB)); |
| |
| EXPECT_CALL(mock_leveldb_factory, OpenLevelDB(_, _, _, _)).Times(Exactly(4)); |
| EXPECT_CALL(mock_leveldb_factory, DestroyLevelDB(_)).Times(Exactly(0)); |
| |
| busted_factory.SetOpenError(MakeIOError( |
| "some filename", "some message", leveldb_env::kNewLogger, ENOSPC)); |
| scoped_refptr<IndexedDBBackingStore> backing_store = |
| IndexedDBBackingStore::Open(factory, |
| origin, |
| path, |
| request_context, |
| &data_loss, |
| &data_loss_reason, |
| &disk_full, |
| &mock_leveldb_factory, |
| task_runner, |
| clean_journal, |
| &s); |
| ASSERT_TRUE(s.IsIOError()); |
| |
| busted_factory.SetOpenError(MakeIOError("some filename", |
| "some message", |
| leveldb_env::kNewLogger, |
| base::File::FILE_ERROR_NO_MEMORY)); |
| scoped_refptr<IndexedDBBackingStore> backing_store2 = |
| IndexedDBBackingStore::Open(factory, |
| origin, |
| path, |
| request_context, |
| &data_loss, |
| &data_loss_reason, |
| &disk_full, |
| &mock_leveldb_factory, |
| task_runner, |
| clean_journal, |
| &s); |
| ASSERT_TRUE(s.IsIOError()); |
| |
| busted_factory.SetOpenError(MakeIOError( |
| "some filename", "some message", leveldb_env::kNewLogger, EIO)); |
| scoped_refptr<IndexedDBBackingStore> backing_store3 = |
| IndexedDBBackingStore::Open(factory, |
| origin, |
| path, |
| request_context, |
| &data_loss, |
| &data_loss_reason, |
| &disk_full, |
| &mock_leveldb_factory, |
| task_runner, |
| clean_journal, |
| &s); |
| ASSERT_TRUE(s.IsIOError()); |
| |
| busted_factory.SetOpenError(MakeIOError("some filename", |
| "some message", |
| leveldb_env::kNewLogger, |
| base::File::FILE_ERROR_FAILED)); |
| scoped_refptr<IndexedDBBackingStore> backing_store4 = |
| IndexedDBBackingStore::Open(factory, |
| origin, |
| path, |
| request_context, |
| &data_loss, |
| &data_loss_reason, |
| &disk_full, |
| &mock_leveldb_factory, |
| task_runner, |
| clean_journal, |
| &s); |
| ASSERT_TRUE(s.IsIOError()); |
| } |
| |
| } // namespace |