| Index: net/disk_cache/backend_unittest.cc
|
| ===================================================================
|
| --- net/disk_cache/backend_unittest.cc (revision 102424)
|
| +++ net/disk_cache/backend_unittest.cc (working copy)
|
| @@ -15,6 +15,7 @@
|
| #include "net/disk_cache/cache_util.h"
|
| #include "net/disk_cache/disk_cache_test_base.h"
|
| #include "net/disk_cache/disk_cache_test_util.h"
|
| +#include "net/disk_cache/entry_impl.h"
|
| #include "net/disk_cache/histogram_macros.h"
|
| #include "net/disk_cache/mapped_file.h"
|
| #include "net/disk_cache/mem_backend_impl.h"
|
| @@ -51,6 +52,12 @@
|
| void BackendRecoverWithEviction();
|
| void BackendInvalidEntry2();
|
| void BackendInvalidEntry3();
|
| + void BackendInvalidEntry7();
|
| + void BackendInvalidEntry8();
|
| + void BackendInvalidEntry9(bool eviction);
|
| + void BackendInvalidEntry10(bool eviction);
|
| + void BackendInvalidEntry11(bool eviction);
|
| + void BackendTrimInvalidEntry12();
|
| void BackendNotMarkedButDirty(const std::string& name);
|
| void BackendDoomAll();
|
| void BackendDoomAll2();
|
| @@ -1499,6 +1506,339 @@
|
| entry->Close();
|
| }
|
|
|
| +// Tests handling of corrupt entries by keeping the rankings node around, with
|
| +// a fatal failure.
|
| +void DiskCacheBackendTest::BackendInvalidEntry7() {
|
| + SetDirectMode();
|
| + const int kSize = 0x3000; // 12 kB.
|
| + SetMaxSize(kSize * 10);
|
| + InitCache();
|
| +
|
| + std::string first("some key");
|
| + std::string second("something else");
|
| + disk_cache::Entry* entry;
|
| + ASSERT_EQ(net::OK, CreateEntry(first, &entry));
|
| + entry->Close();
|
| + ASSERT_EQ(net::OK, CreateEntry(second, &entry));
|
| +
|
| + // Corrupt this entry.
|
| + disk_cache::EntryImpl* entry_impl =
|
| + static_cast<disk_cache::EntryImpl*>(entry);
|
| +
|
| + entry_impl->rankings()->Data()->next = 0;
|
| + entry_impl->rankings()->Store();
|
| + entry->Close();
|
| + FlushQueueForTest();
|
| + EXPECT_EQ(2, cache_->GetEntryCount());
|
| +
|
| + // This should detect the bad entry.
|
| + EXPECT_NE(net::OK, OpenEntry(second, &entry));
|
| + EXPECT_EQ(1, cache_->GetEntryCount());
|
| +
|
| + // We should delete the cache. The list still has a corrupt node.
|
| + void* iter = NULL;
|
| + EXPECT_NE(net::OK, OpenNextEntry(&iter, &entry));
|
| + EXPECT_EQ(0, cache_->GetEntryCount());
|
| +}
|
| +
|
| +TEST_F(DiskCacheBackendTest, InvalidEntry7) {
|
| + BackendInvalidEntry7();
|
| +}
|
| +
|
| +TEST_F(DiskCacheBackendTest, NewEvictionInvalidEntry7) {
|
| + SetNewEviction();
|
| + BackendInvalidEntry7();
|
| +}
|
| +
|
| +// Tests handling of corrupt entries by keeping the rankings node around, with
|
| +// a non fatal failure.
|
| +void DiskCacheBackendTest::BackendInvalidEntry8() {
|
| + SetDirectMode();
|
| + const int kSize = 0x3000; // 12 kB
|
| + SetMaxSize(kSize * 10);
|
| + InitCache();
|
| +
|
| + std::string first("some key");
|
| + std::string second("something else");
|
| + disk_cache::Entry* entry;
|
| + ASSERT_EQ(net::OK, CreateEntry(first, &entry));
|
| + entry->Close();
|
| + ASSERT_EQ(net::OK, CreateEntry(second, &entry));
|
| +
|
| + // Corrupt this entry.
|
| + disk_cache::EntryImpl* entry_impl =
|
| + static_cast<disk_cache::EntryImpl*>(entry);
|
| +
|
| + entry_impl->rankings()->Data()->contents = 0;
|
| + entry_impl->rankings()->Store();
|
| + entry->Close();
|
| + FlushQueueForTest();
|
| + EXPECT_EQ(2, cache_->GetEntryCount());
|
| +
|
| + // This should detect the bad entry.
|
| + EXPECT_NE(net::OK, OpenEntry(second, &entry));
|
| + EXPECT_EQ(1, cache_->GetEntryCount());
|
| +
|
| + // We should not delete the cache.
|
| + void* iter = NULL;
|
| + ASSERT_EQ(net::OK, OpenNextEntry(&iter, &entry));
|
| + entry->Close();
|
| + EXPECT_NE(net::OK, OpenNextEntry(&iter, &entry));
|
| + EXPECT_EQ(1, cache_->GetEntryCount());
|
| +}
|
| +
|
| +TEST_F(DiskCacheBackendTest, InvalidEntry8) {
|
| + BackendInvalidEntry8();
|
| +}
|
| +
|
| +TEST_F(DiskCacheBackendTest, NewEvictionInvalidEntry8) {
|
| + SetNewEviction();
|
| + BackendInvalidEntry8();
|
| +}
|
| +
|
| +// Tests handling of corrupt entries detected by enumerations. Note that these
|
| +// tests (xx9 to xx11) are basically just going though slightly different
|
| +// codepaths so they are tighlty coupled with the code, but that is better than
|
| +// not testing error handling code.
|
| +void DiskCacheBackendTest::BackendInvalidEntry9(bool eviction) {
|
| + SetDirectMode();
|
| + const int kSize = 0x3000; // 12 kB.
|
| + SetMaxSize(kSize * 10);
|
| + InitCache();
|
| +
|
| + std::string first("some key");
|
| + std::string second("something else");
|
| + disk_cache::Entry* entry;
|
| + ASSERT_EQ(net::OK, CreateEntry(first, &entry));
|
| + entry->Close();
|
| + ASSERT_EQ(net::OK, CreateEntry(second, &entry));
|
| +
|
| + // Corrupt this entry.
|
| + disk_cache::EntryImpl* entry_impl =
|
| + static_cast<disk_cache::EntryImpl*>(entry);
|
| +
|
| + entry_impl->entry()->Data()->state = 0xbad;
|
| + entry_impl->entry()->Store();
|
| + entry->Close();
|
| + FlushQueueForTest();
|
| + EXPECT_EQ(2, cache_->GetEntryCount());
|
| +
|
| + if (eviction) {
|
| + TrimForTest(false);
|
| + EXPECT_EQ(1, cache_->GetEntryCount());
|
| + TrimForTest(false);
|
| + EXPECT_EQ(1, cache_->GetEntryCount());
|
| + } else {
|
| + // We should detect the problem through the list, but we should not delete
|
| + // the entry, just fail the iteration.
|
| + void* iter = NULL;
|
| + EXPECT_NE(net::OK, OpenNextEntry(&iter, &entry));
|
| +
|
| + // Now a full iteration will work, and return one entry.
|
| + ASSERT_EQ(net::OK, OpenNextEntry(&iter, &entry));
|
| + entry->Close();
|
| + EXPECT_NE(net::OK, OpenNextEntry(&iter, &entry));
|
| +
|
| + // This should detect what's left of the bad entry.
|
| + EXPECT_NE(net::OK, OpenEntry(second, &entry));
|
| + EXPECT_EQ(2, cache_->GetEntryCount());
|
| + }
|
| + DisableIntegrityCheck();
|
| +}
|
| +
|
| +TEST_F(DiskCacheBackendTest, InvalidEntry9) {
|
| + BackendInvalidEntry9(false);
|
| +}
|
| +
|
| +TEST_F(DiskCacheBackendTest, NewEvictionInvalidEntry9) {
|
| + SetNewEviction();
|
| + BackendInvalidEntry9(false);
|
| +}
|
| +
|
| +TEST_F(DiskCacheBackendTest, TrimInvalidEntry9) {
|
| + BackendInvalidEntry9(true);
|
| +}
|
| +
|
| +TEST_F(DiskCacheBackendTest, NewEvictionTrimInvalidEntry9) {
|
| + SetNewEviction();
|
| + BackendInvalidEntry9(true);
|
| +}
|
| +
|
| +// Tests handling of corrupt entries detected by enumerations.
|
| +void DiskCacheBackendTest::BackendInvalidEntry10(bool eviction) {
|
| + SetDirectMode();
|
| + const int kSize = 0x3000; // 12 kB.
|
| + SetMaxSize(kSize * 10);
|
| + SetNewEviction();
|
| + InitCache();
|
| +
|
| + std::string first("some key");
|
| + std::string second("something else");
|
| + disk_cache::Entry* entry;
|
| + ASSERT_EQ(net::OK, CreateEntry(first, &entry));
|
| + entry->Close();
|
| + ASSERT_EQ(net::OK, OpenEntry(first, &entry));
|
| + EXPECT_EQ(0, WriteData(entry, 0, 200, NULL, 0, false));
|
| + entry->Close();
|
| + ASSERT_EQ(net::OK, CreateEntry(second, &entry));
|
| +
|
| + // Corrupt this entry.
|
| + disk_cache::EntryImpl* entry_impl =
|
| + static_cast<disk_cache::EntryImpl*>(entry);
|
| +
|
| + entry_impl->entry()->Data()->state = 0xbad;
|
| + entry_impl->entry()->Store();
|
| + entry->Close();
|
| + ASSERT_EQ(net::OK, CreateEntry("third", &entry));
|
| + entry->Close();
|
| + EXPECT_EQ(3, cache_->GetEntryCount());
|
| +
|
| + // We have:
|
| + // List 0: third -> second (bad).
|
| + // List 1: first.
|
| +
|
| + if (eviction) {
|
| + // Detection order: second -> first -> third.
|
| + TrimForTest(false);
|
| + EXPECT_EQ(3, cache_->GetEntryCount());
|
| + TrimForTest(false);
|
| + EXPECT_EQ(2, cache_->GetEntryCount());
|
| + TrimForTest(false);
|
| + EXPECT_EQ(1, cache_->GetEntryCount());
|
| + } else {
|
| + // Detection order: third -> second -> first.
|
| + // We should detect the problem through the list, but we should not delete
|
| + // the entry.
|
| + void* iter = NULL;
|
| + ASSERT_EQ(net::OK, OpenNextEntry(&iter, &entry));
|
| + entry->Close();
|
| + ASSERT_EQ(net::OK, OpenNextEntry(&iter, &entry));
|
| + EXPECT_EQ(first, entry->GetKey());
|
| + entry->Close();
|
| + EXPECT_NE(net::OK, OpenNextEntry(&iter, &entry));
|
| + }
|
| + DisableIntegrityCheck();
|
| +}
|
| +
|
| +TEST_F(DiskCacheBackendTest, InvalidEntry10) {
|
| + BackendInvalidEntry10(false);
|
| +}
|
| +
|
| +TEST_F(DiskCacheBackendTest, TrimInvalidEntry10) {
|
| + BackendInvalidEntry10(true);
|
| +}
|
| +
|
| +// Tests handling of corrupt entries detected by enumerations.
|
| +void DiskCacheBackendTest::BackendInvalidEntry11(bool eviction) {
|
| + SetDirectMode();
|
| + const int kSize = 0x3000; // 12 kB.
|
| + SetMaxSize(kSize * 10);
|
| + SetNewEviction();
|
| + InitCache();
|
| +
|
| + std::string first("some key");
|
| + std::string second("something else");
|
| + disk_cache::Entry* entry;
|
| + ASSERT_EQ(net::OK, CreateEntry(first, &entry));
|
| + entry->Close();
|
| + ASSERT_EQ(net::OK, OpenEntry(first, &entry));
|
| + EXPECT_EQ(0, WriteData(entry, 0, 200, NULL, 0, false));
|
| + entry->Close();
|
| + ASSERT_EQ(net::OK, CreateEntry(second, &entry));
|
| + entry->Close();
|
| + ASSERT_EQ(net::OK, OpenEntry(second, &entry));
|
| + EXPECT_EQ(0, WriteData(entry, 0, 200, NULL, 0, false));
|
| +
|
| + // Corrupt this entry.
|
| + disk_cache::EntryImpl* entry_impl =
|
| + static_cast<disk_cache::EntryImpl*>(entry);
|
| +
|
| + entry_impl->entry()->Data()->state = 0xbad;
|
| + entry_impl->entry()->Store();
|
| + entry->Close();
|
| + ASSERT_EQ(net::OK, CreateEntry("third", &entry));
|
| + entry->Close();
|
| + FlushQueueForTest();
|
| + EXPECT_EQ(3, cache_->GetEntryCount());
|
| +
|
| + // We have:
|
| + // List 0: third.
|
| + // List 1: second (bad) -> first.
|
| +
|
| + if (eviction) {
|
| + // Detection order: third -> first -> second.
|
| + TrimForTest(false);
|
| + EXPECT_EQ(2, cache_->GetEntryCount());
|
| + TrimForTest(false);
|
| + EXPECT_EQ(1, cache_->GetEntryCount());
|
| + TrimForTest(false);
|
| + EXPECT_EQ(1, cache_->GetEntryCount());
|
| + } else {
|
| + // Detection order: third -> second.
|
| + // We should detect the problem through the list, but we should not delete
|
| + // the entry, just fail the iteration.
|
| + void* iter = NULL;
|
| + ASSERT_EQ(net::OK, OpenNextEntry(&iter, &entry));
|
| + entry->Close();
|
| + EXPECT_NE(net::OK, OpenNextEntry(&iter, &entry));
|
| +
|
| + // Now a full iteration will work, and return two entries.
|
| + ASSERT_EQ(net::OK, OpenNextEntry(&iter, &entry));
|
| + entry->Close();
|
| + ASSERT_EQ(net::OK, OpenNextEntry(&iter, &entry));
|
| + entry->Close();
|
| + EXPECT_NE(net::OK, OpenNextEntry(&iter, &entry));
|
| + }
|
| + DisableIntegrityCheck();
|
| +}
|
| +
|
| +TEST_F(DiskCacheBackendTest, InvalidEntry11) {
|
| + BackendInvalidEntry11(false);
|
| +}
|
| +
|
| +TEST_F(DiskCacheBackendTest, TrimInvalidEntry11) {
|
| + BackendInvalidEntry11(true);
|
| +}
|
| +
|
| +// Tests handling of corrupt entries in the middle of a long eviction run.
|
| +void DiskCacheBackendTest::BackendTrimInvalidEntry12() {
|
| + SetDirectMode();
|
| + const int kSize = 0x3000; // 12 kB
|
| + SetMaxSize(kSize * 10);
|
| + InitCache();
|
| +
|
| + std::string first("some key");
|
| + std::string second("something else");
|
| + disk_cache::Entry* entry;
|
| + ASSERT_EQ(net::OK, CreateEntry(first, &entry));
|
| + entry->Close();
|
| + ASSERT_EQ(net::OK, CreateEntry(second, &entry));
|
| +
|
| + // Corrupt this entry.
|
| + disk_cache::EntryImpl* entry_impl =
|
| + static_cast<disk_cache::EntryImpl*>(entry);
|
| +
|
| + entry_impl->entry()->Data()->state = 0xbad;
|
| + entry_impl->entry()->Store();
|
| + entry->Close();
|
| + ASSERT_EQ(net::OK, CreateEntry("third", &entry));
|
| + entry->Close();
|
| + ASSERT_EQ(net::OK, CreateEntry("fourth", &entry));
|
| + TrimForTest(true);
|
| + EXPECT_EQ(1, cache_->GetEntryCount());
|
| + entry->Close();
|
| + DisableIntegrityCheck();
|
| +}
|
| +
|
| +TEST_F(DiskCacheBackendTest, TrimInvalidEntry12) {
|
| + BackendTrimInvalidEntry12();
|
| +}
|
| +
|
| +TEST_F(DiskCacheBackendTest, NewEvictionTrimInvalidEntry12) {
|
| + SetNewEviction();
|
| + BackendTrimInvalidEntry12();
|
| +}
|
| +
|
| // We want to be able to deal with abnormal dirty entries.
|
| void DiskCacheBackendTest::BackendNotMarkedButDirty(const std::string& name) {
|
| ASSERT_TRUE(CopyTestCache(name));
|
|
|