| // Copyright (c) 2006-2008 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 "base/basictypes.h" |
| #include "base/file_util.h" |
| #include "base/path_service.h" |
| #include "base/platform_thread.h" |
| #include "base/string_util.h" |
| #include "net/base/io_buffer.h" |
| #include "net/base/net_errors.h" |
| #include "net/disk_cache/backend_impl.h" |
| #include "net/disk_cache/disk_cache_test_base.h" |
| #include "net/disk_cache/disk_cache_test_util.h" |
| #include "net/disk_cache/mapped_file.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using base::Time; |
| |
| namespace { |
| |
| // Copies a set of cache files from the data folder to the test folder. |
| bool CopyTestCache(const std::wstring& name) { |
| FilePath path; |
| PathService::Get(base::DIR_SOURCE_ROOT, &path); |
| path = path.AppendASCII("net"); |
| path = path.AppendASCII("data"); |
| path = path.AppendASCII("cache_tests"); |
| path = path.Append(FilePath::FromWStringHack(name)); |
| |
| FilePath dest = GetCacheFilePath(); |
| if (!DeleteCache(dest)) |
| return false; |
| return file_util::CopyDirectory(path, dest, false); |
| } |
| |
| } // namespace |
| |
| // Tests that can run with different types of caches. |
| class DiskCacheBackendTest : public DiskCacheTestWithCache { |
| protected: |
| void BackendBasics(); |
| void BackendKeying(); |
| void BackendSetSize(); |
| void BackendLoad(); |
| void BackendValidEntry(); |
| void BackendInvalidEntry(); |
| void BackendInvalidEntryRead(); |
| void BackendInvalidEntryWithLoad(); |
| void BackendTrimInvalidEntry(); |
| void BackendTrimInvalidEntry2(); |
| void BackendEnumerations(); |
| void BackendEnumerations2(); |
| void BackendInvalidEntryEnumeration(); |
| void BackendFixEnumerators(); |
| void BackendDoomRecent(); |
| void BackendDoomBetween(); |
| void BackendTransaction(const std::wstring& name, int num_entries, bool load); |
| void BackendRecoverInsert(); |
| void BackendRecoverRemove(); |
| void BackendInvalidEntry2(); |
| void BackendNotMarkedButDirty(const std::wstring& name); |
| void BackendDoomAll(); |
| void BackendDoomAll2(); |
| void BackendInvalidRankings(); |
| void BackendInvalidRankings2(); |
| void BackendDisable(); |
| void BackendDisable2(); |
| void BackendDisable3(); |
| void BackendDisable4(); |
| }; |
| |
| void DiskCacheBackendTest::BackendBasics() { |
| InitCache(); |
| disk_cache::Entry *entry1 = NULL, *entry2 = NULL; |
| EXPECT_FALSE(cache_->OpenEntry("the first key", &entry1)); |
| ASSERT_TRUE(cache_->CreateEntry("the first key", &entry1)); |
| ASSERT_TRUE(NULL != entry1); |
| entry1->Close(); |
| entry1 = NULL; |
| |
| ASSERT_TRUE(cache_->OpenEntry("the first key", &entry1)); |
| ASSERT_TRUE(NULL != entry1); |
| entry1->Close(); |
| entry1 = NULL; |
| |
| EXPECT_FALSE(cache_->CreateEntry("the first key", &entry1)); |
| ASSERT_TRUE(cache_->OpenEntry("the first key", &entry1)); |
| EXPECT_FALSE(cache_->OpenEntry("some other key", &entry2)); |
| ASSERT_TRUE(cache_->CreateEntry("some other key", &entry2)); |
| ASSERT_TRUE(NULL != entry1); |
| ASSERT_TRUE(NULL != entry2); |
| EXPECT_EQ(2, cache_->GetEntryCount()); |
| |
| disk_cache::Entry* entry3 = NULL; |
| ASSERT_TRUE(cache_->OpenEntry("some other key", &entry3)); |
| ASSERT_TRUE(NULL != entry3); |
| EXPECT_TRUE(entry2 == entry3); |
| EXPECT_EQ(2, cache_->GetEntryCount()); |
| |
| EXPECT_TRUE(cache_->DoomEntry("some other key")); |
| EXPECT_EQ(1, cache_->GetEntryCount()); |
| entry1->Close(); |
| entry2->Close(); |
| entry3->Close(); |
| |
| EXPECT_TRUE(cache_->DoomEntry("the first key")); |
| EXPECT_EQ(0, cache_->GetEntryCount()); |
| |
| ASSERT_TRUE(cache_->CreateEntry("the first key", &entry1)); |
| ASSERT_TRUE(cache_->CreateEntry("some other key", &entry2)); |
| entry1->Doom(); |
| entry1->Close(); |
| EXPECT_TRUE(cache_->DoomEntry("some other key")); |
| EXPECT_EQ(0, cache_->GetEntryCount()); |
| entry2->Close(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, Basics) { |
| BackendBasics(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionBasics) { |
| SetNewEviction(); |
| BackendBasics(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, MemoryOnlyBasics) { |
| SetMemoryOnlyMode(); |
| BackendBasics(); |
| } |
| |
| void DiskCacheBackendTest::BackendKeying() { |
| InitCache(); |
| const char* kName1 = "the first key"; |
| const char* kName2 = "the first Key"; |
| disk_cache::Entry *entry1, *entry2; |
| ASSERT_TRUE(cache_->CreateEntry(kName1, &entry1)); |
| |
| ASSERT_TRUE(cache_->CreateEntry(kName2, &entry2)); |
| EXPECT_TRUE(entry1 != entry2) << "Case sensitive"; |
| entry2->Close(); |
| |
| char buffer[30]; |
| base::strlcpy(buffer, kName1, arraysize(buffer)); |
| ASSERT_TRUE(cache_->OpenEntry(buffer, &entry2)); |
| EXPECT_TRUE(entry1 == entry2); |
| entry2->Close(); |
| |
| base::strlcpy(buffer + 1, kName1, arraysize(buffer) - 1); |
| ASSERT_TRUE(cache_->OpenEntry(buffer + 1, &entry2)); |
| EXPECT_TRUE(entry1 == entry2); |
| entry2->Close(); |
| |
| base::strlcpy(buffer + 3, kName1, arraysize(buffer) - 3); |
| ASSERT_TRUE(cache_->OpenEntry(buffer + 3, &entry2)); |
| EXPECT_TRUE(entry1 == entry2); |
| entry2->Close(); |
| |
| // Now verify long keys. |
| char buffer2[20000]; |
| memset(buffer2, 's', sizeof(buffer2)); |
| buffer2[1023] = '\0'; |
| ASSERT_TRUE(cache_->CreateEntry(buffer2, &entry2)) << "key on block file"; |
| entry2->Close(); |
| |
| buffer2[1023] = 'g'; |
| buffer2[19999] = '\0'; |
| ASSERT_TRUE(cache_->CreateEntry(buffer2, &entry2)) << "key on external file"; |
| entry2->Close(); |
| entry1->Close(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, Keying) { |
| BackendKeying(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionKeying) { |
| SetNewEviction(); |
| BackendKeying(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, MemoryOnlyKeying) { |
| SetMemoryOnlyMode(); |
| BackendKeying(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, ExternalFiles) { |
| InitCache(); |
| // First, lets create a file on the folder. |
| FilePath filename = GetCacheFilePath().AppendASCII("f_000001"); |
| |
| const int kSize = 50; |
| scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); |
| CacheTestFillBuffer(buffer1->data(), kSize, false); |
| ASSERT_EQ(kSize, file_util::WriteFile(filename, buffer1->data(), kSize)); |
| |
| // Now let's create a file with the cache. |
| disk_cache::Entry* entry; |
| ASSERT_TRUE(cache_->CreateEntry("key", &entry)); |
| ASSERT_EQ(0, entry->WriteData(0, 20000, buffer1, 0, NULL, false)); |
| entry->Close(); |
| |
| // And verify that the first file is still there. |
| scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize); |
| ASSERT_EQ(kSize, file_util::ReadFile(filename, buffer2->data(), kSize)); |
| EXPECT_EQ(0, memcmp(buffer1->data(), buffer2->data(), kSize)); |
| } |
| |
| TEST_F(DiskCacheTest, ShutdownWithPendingIO) { |
| SimpleCallbackTest callback; |
| |
| { |
| FilePath path = GetCacheFilePath(); |
| ASSERT_TRUE(DeleteCache(path)); |
| |
| disk_cache::Backend* cache = |
| disk_cache::CreateCacheBackend(path, false, 0, net::DISK_CACHE); |
| |
| disk_cache::Entry* entry; |
| ASSERT_TRUE(cache->CreateEntry("some key", &entry)); |
| |
| const int kSize = 25000; |
| scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); |
| CacheTestFillBuffer(buffer->data(), kSize, false); |
| |
| for (int i = 0; i < 10 * 1024 * 1024; i += 64 * 1024) { |
| int rv = entry->WriteData(0, i, buffer, kSize, &callback, false); |
| if (rv == net::ERR_IO_PENDING) |
| break; |
| EXPECT_EQ(kSize, rv); |
| } |
| |
| entry->Close(); |
| |
| // The cache destructor will see one pending operation here. |
| delete cache; |
| } |
| |
| MessageLoop::current()->RunAllPending(); |
| } |
| |
| void DiskCacheBackendTest::BackendSetSize() { |
| SetDirectMode(); |
| const int cache_size = 0x10000; // 64 kB |
| SetMaxSize(cache_size); |
| InitCache(); |
| |
| std::string first("some key"); |
| std::string second("something else"); |
| disk_cache::Entry* entry; |
| ASSERT_TRUE(cache_->CreateEntry(first, &entry)); |
| |
| scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(cache_size); |
| memset(buffer->data(), 0, cache_size); |
| EXPECT_EQ(cache_size / 10, entry->WriteData(0, 0, buffer, cache_size / 10, |
| NULL, false)) << "normal file"; |
| |
| EXPECT_EQ(net::ERR_FAILED, entry->WriteData(1, 0, buffer, cache_size / 5, |
| NULL, false)) << "file size above the limit"; |
| |
| // By doubling the total size, we make this file cacheable. |
| SetMaxSize(cache_size * 2); |
| EXPECT_EQ(cache_size / 5, entry->WriteData(1, 0, buffer, cache_size / 5, |
| NULL, false)); |
| |
| // Let's fill up the cache!. |
| SetMaxSize(cache_size * 10); |
| EXPECT_EQ(cache_size * 3 / 4, entry->WriteData(0, 0, buffer, |
| cache_size * 3 / 4, NULL, false)); |
| entry->Close(); |
| |
| SetMaxSize(cache_size); |
| |
| // The cache is 95% full. |
| |
| ASSERT_TRUE(cache_->CreateEntry(second, &entry)); |
| EXPECT_EQ(cache_size / 10, entry->WriteData(0, 0, buffer, cache_size / 10, |
| NULL, false)) << "trim the cache"; |
| entry->Close(); |
| |
| EXPECT_FALSE(cache_->OpenEntry(first, &entry)); |
| ASSERT_TRUE(cache_->OpenEntry(second, &entry)); |
| EXPECT_EQ(cache_size / 10, entry->GetDataSize(0)); |
| entry->Close(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, SetSize) { |
| BackendSetSize(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionSetSize) { |
| SetNewEviction(); |
| BackendSetSize(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, MemoryOnlySetSize) { |
| SetMemoryOnlyMode(); |
| BackendSetSize(); |
| } |
| |
| void DiskCacheBackendTest::BackendLoad() { |
| InitCache(); |
| int seed = static_cast<int>(Time::Now().ToInternalValue()); |
| srand(seed); |
| |
| disk_cache::Entry* entries[100]; |
| for (int i = 0; i < 100; i++) { |
| std::string key = GenerateKey(true); |
| ASSERT_TRUE(cache_->CreateEntry(key, &entries[i])); |
| } |
| EXPECT_EQ(100, cache_->GetEntryCount()); |
| |
| for (int i = 0; i < 100; i++) { |
| int source1 = rand() % 100; |
| int source2 = rand() % 100; |
| disk_cache::Entry* temp = entries[source1]; |
| entries[source1] = entries[source2]; |
| entries[source2] = temp; |
| } |
| |
| for (int i = 0; i < 100; i++) { |
| disk_cache::Entry* entry; |
| ASSERT_TRUE(cache_->OpenEntry(entries[i]->GetKey(), &entry)); |
| EXPECT_TRUE(entry == entries[i]); |
| entry->Close(); |
| entries[i]->Doom(); |
| entries[i]->Close(); |
| } |
| EXPECT_EQ(0, cache_->GetEntryCount()); |
| } |
| |
| TEST_F(DiskCacheBackendTest, Load) { |
| // Work with a tiny index table (16 entries) |
| SetMask(0xf); |
| SetMaxSize(0x100000); |
| BackendLoad(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionLoad) { |
| SetNewEviction(); |
| // Work with a tiny index table (16 entries) |
| SetMask(0xf); |
| SetMaxSize(0x100000); |
| BackendLoad(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, MemoryOnlyLoad) { |
| // Work with a tiny index table (16 entries) |
| SetMaxSize(0x100000); |
| SetMemoryOnlyMode(); |
| BackendLoad(); |
| } |
| |
| // Before looking for invalid entries, let's check a valid entry. |
| void DiskCacheBackendTest::BackendValidEntry() { |
| SetDirectMode(); |
| InitCache(); |
| |
| std::string key("Some key"); |
| disk_cache::Entry* entry1; |
| ASSERT_TRUE(cache_->CreateEntry(key, &entry1)); |
| |
| const int kSize = 50; |
| scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); |
| memset(buffer1->data(), 0, kSize); |
| base::strlcpy(buffer1->data(), "And the data to save", kSize); |
| EXPECT_EQ(kSize, entry1->WriteData(0, 0, buffer1, kSize, NULL, false)); |
| entry1->Close(); |
| SimulateCrash(); |
| |
| ASSERT_TRUE(cache_->OpenEntry(key, &entry1)); |
| |
| scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize); |
| memset(buffer2->data(), 0, kSize); |
| EXPECT_EQ(kSize, entry1->ReadData(0, 0, buffer2, kSize, NULL)); |
| entry1->Close(); |
| EXPECT_STREQ(buffer1->data(), buffer2->data()); |
| } |
| |
| TEST_F(DiskCacheBackendTest, ValidEntry) { |
| BackendValidEntry(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionValidEntry) { |
| SetNewEviction(); |
| BackendValidEntry(); |
| } |
| |
| // The same logic of the previous test (ValidEntry), but this time force the |
| // entry to be invalid, simulating a crash in the middle. |
| // We'll be leaking memory from this test. |
| void DiskCacheBackendTest::BackendInvalidEntry() { |
| // Use the implementation directly... we need to simulate a crash. |
| SetDirectMode(); |
| InitCache(); |
| |
| std::string key("Some key"); |
| disk_cache::Entry* entry1; |
| ASSERT_TRUE(cache_->CreateEntry(key, &entry1)); |
| |
| const int kSize = 50; |
| scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); |
| memset(buffer1->data(), 0, kSize); |
| base::strlcpy(buffer1->data(), "And the data to save", kSize); |
| EXPECT_EQ(kSize, entry1->WriteData(0, 0, buffer1, kSize, NULL, false)); |
| SimulateCrash(); |
| |
| EXPECT_FALSE(cache_->OpenEntry(key, &entry1)); |
| EXPECT_EQ(0, cache_->GetEntryCount()); |
| } |
| |
| // This and the other intentionally leaky tests below are excluded from |
| // purify and valgrind runs by naming them in the files |
| // net/data/purify/net_unittests.exe.gtest.txt and |
| // net/data/valgrind/net_unittests.gtest.txt |
| // The scripts tools/{purify,valgrind}/chrome_tests.sh |
| // read those files and pass the appropriate --gtest_filter to net_unittests. |
| TEST_F(DiskCacheBackendTest, InvalidEntry) { |
| BackendInvalidEntry(); |
| } |
| |
| // We'll be leaking memory from this test. |
| TEST_F(DiskCacheBackendTest, NewEvictionInvalidEntry) { |
| SetNewEviction(); |
| BackendInvalidEntry(); |
| } |
| |
| // Almost the same test, but this time crash the cache after reading an entry. |
| // We'll be leaking memory from this test. |
| void DiskCacheBackendTest::BackendInvalidEntryRead() { |
| // Use the implementation directly... we need to simulate a crash. |
| SetDirectMode(); |
| InitCache(); |
| |
| std::string key("Some key"); |
| disk_cache::Entry* entry1; |
| ASSERT_TRUE(cache_->CreateEntry(key, &entry1)); |
| |
| const int kSize = 50; |
| scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); |
| memset(buffer1->data(), 0, kSize); |
| base::strlcpy(buffer1->data(), "And the data to save", kSize); |
| EXPECT_EQ(kSize, entry1->WriteData(0, 0, buffer1, kSize, NULL, false)); |
| entry1->Close(); |
| ASSERT_TRUE(cache_->OpenEntry(key, &entry1)); |
| EXPECT_EQ(kSize, entry1->ReadData(0, 0, buffer1, kSize, NULL)); |
| |
| SimulateCrash(); |
| |
| EXPECT_FALSE(cache_->OpenEntry(key, &entry1)); |
| EXPECT_EQ(0, cache_->GetEntryCount()); |
| } |
| |
| // We'll be leaking memory from this test. |
| TEST_F(DiskCacheBackendTest, InvalidEntryRead) { |
| BackendInvalidEntryRead(); |
| } |
| |
| // We'll be leaking memory from this test. |
| TEST_F(DiskCacheBackendTest, NewEvictionInvalidEntryRead) { |
| SetNewEviction(); |
| BackendInvalidEntryRead(); |
| } |
| |
| // We'll be leaking memory from this test. |
| void DiskCacheBackendTest::BackendInvalidEntryWithLoad() { |
| // Work with a tiny index table (16 entries) |
| SetMask(0xf); |
| SetMaxSize(0x100000); |
| InitCache(); |
| |
| int seed = static_cast<int>(Time::Now().ToInternalValue()); |
| srand(seed); |
| |
| const int kNumEntries = 100; |
| disk_cache::Entry* entries[kNumEntries]; |
| for (int i = 0; i < kNumEntries; i++) { |
| std::string key = GenerateKey(true); |
| ASSERT_TRUE(cache_->CreateEntry(key, &entries[i])); |
| } |
| EXPECT_EQ(kNumEntries, cache_->GetEntryCount()); |
| |
| for (int i = 0; i < kNumEntries; i++) { |
| int source1 = rand() % kNumEntries; |
| int source2 = rand() % kNumEntries; |
| disk_cache::Entry* temp = entries[source1]; |
| entries[source1] = entries[source2]; |
| entries[source2] = temp; |
| } |
| |
| std::string keys[kNumEntries]; |
| for (int i = 0; i < kNumEntries; i++) { |
| keys[i] = entries[i]->GetKey(); |
| if (i < kNumEntries / 2) |
| entries[i]->Close(); |
| } |
| |
| SimulateCrash(); |
| |
| for (int i = kNumEntries / 2; i < kNumEntries; i++) { |
| disk_cache::Entry* entry; |
| EXPECT_FALSE(cache_->OpenEntry(keys[i], &entry)); |
| } |
| |
| for (int i = 0; i < kNumEntries / 2; i++) { |
| disk_cache::Entry* entry; |
| EXPECT_TRUE(cache_->OpenEntry(keys[i], &entry)); |
| entry->Close(); |
| } |
| |
| EXPECT_EQ(kNumEntries / 2, cache_->GetEntryCount()); |
| } |
| |
| // We'll be leaking memory from this test. |
| TEST_F(DiskCacheBackendTest, InvalidEntryWithLoad) { |
| BackendInvalidEntryWithLoad(); |
| } |
| |
| // We'll be leaking memory from this test. |
| TEST_F(DiskCacheBackendTest, NewEvictionInvalidEntryWithLoad) { |
| SetNewEviction(); |
| BackendInvalidEntryWithLoad(); |
| } |
| |
| // We'll be leaking memory from this test. |
| void DiskCacheBackendTest::BackendTrimInvalidEntry() { |
| // Use the implementation directly... we need to simulate a crash. |
| 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_TRUE(cache_->CreateEntry(first, &entry)); |
| |
| scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); |
| memset(buffer->data(), 0, kSize); |
| EXPECT_EQ(kSize, entry->WriteData(0, 0, buffer, kSize, NULL, false)); |
| |
| // Simulate a crash. |
| SimulateCrash(); |
| |
| ASSERT_TRUE(cache_->CreateEntry(second, &entry)); |
| EXPECT_EQ(kSize, entry->WriteData(0, 0, buffer, kSize, NULL, false)); |
| |
| EXPECT_EQ(2, cache_->GetEntryCount()); |
| SetMaxSize(kSize); |
| entry->Close(); // Trim the cache. |
| |
| // If we evicted the entry in less than 20mS, we have one entry in the cache; |
| // if it took more than that, we posted a task and we'll delete the second |
| // entry too. |
| MessageLoop::current()->RunAllPending(); |
| EXPECT_GE(1, cache_->GetEntryCount()); |
| EXPECT_FALSE(cache_->OpenEntry(first, &entry)); |
| } |
| |
| // We'll be leaking memory from this test. |
| TEST_F(DiskCacheBackendTest, TrimInvalidEntry) { |
| BackendTrimInvalidEntry(); |
| } |
| |
| // We'll be leaking memory from this test. |
| TEST_F(DiskCacheBackendTest, NewEvictionTrimInvalidEntry) { |
| SetNewEviction(); |
| BackendTrimInvalidEntry(); |
| } |
| |
| // We'll be leaking memory from this test. |
| void DiskCacheBackendTest::BackendTrimInvalidEntry2() { |
| // Use the implementation directly... we need to simulate a crash. |
| SetDirectMode(); |
| SetMask(0xf); // 16-entry table. |
| |
| const int kSize = 0x3000; // 12 kB |
| SetMaxSize(kSize * 40); |
| InitCache(); |
| |
| scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); |
| memset(buffer->data(), 0, kSize); |
| disk_cache::Entry* entry; |
| |
| // Writing 32 entries to this cache chains most of them. |
| for (int i = 0; i < 32; i++) { |
| std::string key(StringPrintf("some key %d", i)); |
| ASSERT_TRUE(cache_->CreateEntry(key, &entry)); |
| EXPECT_EQ(kSize, entry->WriteData(0, 0, buffer, kSize, NULL, false)); |
| entry->Close(); |
| ASSERT_TRUE(cache_->OpenEntry(key, &entry)); |
| // Note that we are not closing the entries. |
| } |
| |
| // Simulate a crash. |
| SimulateCrash(); |
| |
| ASSERT_TRUE(cache_->CreateEntry("Something else", &entry)); |
| EXPECT_EQ(kSize, entry->WriteData(0, 0, buffer, kSize, NULL, false)); |
| |
| EXPECT_EQ(33, cache_->GetEntryCount()); |
| SetMaxSize(kSize); |
| |
| // For the new eviction code, all corrupt entries are on the second list so |
| // they are not going away that easy. |
| if (new_eviction_) |
| cache_->DoomAllEntries(); |
| |
| entry->Close(); // Trim the cache. |
| |
| // We may abort the eviction before cleaning up everything. |
| MessageLoop::current()->RunAllPending(); |
| EXPECT_GE(30, cache_->GetEntryCount()); |
| } |
| |
| // We'll be leaking memory from this test. |
| TEST_F(DiskCacheBackendTest, TrimInvalidEntry2) { |
| BackendTrimInvalidEntry2(); |
| } |
| |
| // We'll be leaking memory from this test. |
| TEST_F(DiskCacheBackendTest, NewEvictionTrimInvalidEntry2) { |
| SetNewEviction(); |
| BackendTrimInvalidEntry2(); |
| } |
| |
| void DiskCacheBackendTest::BackendEnumerations() { |
| InitCache(); |
| Time initial = Time::Now(); |
| int seed = static_cast<int>(initial.ToInternalValue()); |
| srand(seed); |
| |
| const int kNumEntries = 100; |
| for (int i = 0; i < kNumEntries; i++) { |
| std::string key = GenerateKey(true); |
| disk_cache::Entry* entry; |
| ASSERT_TRUE(cache_->CreateEntry(key, &entry)); |
| entry->Close(); |
| } |
| EXPECT_EQ(kNumEntries, cache_->GetEntryCount()); |
| Time final = Time::Now(); |
| |
| disk_cache::Entry* entry; |
| void* iter = NULL; |
| int count = 0; |
| Time last_modified[kNumEntries]; |
| Time last_used[kNumEntries]; |
| while (cache_->OpenNextEntry(&iter, &entry)) { |
| ASSERT_TRUE(NULL != entry); |
| if (count < kNumEntries) { |
| last_modified[count] = entry->GetLastModified(); |
| last_used[count] = entry->GetLastUsed(); |
| EXPECT_TRUE(initial <= last_modified[count]); |
| EXPECT_TRUE(final >= last_modified[count]); |
| } |
| |
| entry->Close(); |
| count++; |
| }; |
| EXPECT_EQ(kNumEntries, count); |
| |
| iter = NULL; |
| count = 0; |
| // The previous enumeration should not have changed the timestamps. |
| while (cache_->OpenNextEntry(&iter, &entry)) { |
| ASSERT_TRUE(NULL != entry); |
| if (count < kNumEntries) { |
| EXPECT_TRUE(last_modified[count] == entry->GetLastModified()); |
| EXPECT_TRUE(last_used[count] == entry->GetLastUsed()); |
| } |
| entry->Close(); |
| count++; |
| }; |
| EXPECT_EQ(kNumEntries, count); |
| } |
| |
| TEST_F(DiskCacheBackendTest, Enumerations) { |
| BackendEnumerations(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionEnumerations) { |
| SetNewEviction(); |
| BackendEnumerations(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, MemoryOnlyEnumerations) { |
| SetMemoryOnlyMode(); |
| BackendEnumerations(); |
| } |
| |
| // Verifies enumerations while entries are open. |
| void DiskCacheBackendTest::BackendEnumerations2() { |
| InitCache(); |
| const std::string first("first"); |
| const std::string second("second"); |
| disk_cache::Entry *entry1, *entry2; |
| ASSERT_TRUE(cache_->CreateEntry(first, &entry1)); |
| entry1->Close(); |
| ASSERT_TRUE(cache_->CreateEntry(second, &entry2)); |
| entry2->Close(); |
| |
| // Make sure that the timestamp is not the same. |
| PlatformThread::Sleep(20); |
| ASSERT_TRUE(cache_->OpenEntry(second, &entry1)); |
| void* iter = NULL; |
| ASSERT_TRUE(cache_->OpenNextEntry(&iter, &entry2)); |
| ASSERT_EQ(entry2->GetKey(), second); |
| |
| // Two entries and the iterator pointing at "first". |
| entry1->Close(); |
| entry2->Close(); |
| |
| // The iterator should still be valid, se we should not crash. |
| ASSERT_TRUE(cache_->OpenNextEntry(&iter, &entry2)); |
| ASSERT_EQ(entry2->GetKey(), first); |
| entry2->Close(); |
| cache_->EndEnumeration(&iter); |
| } |
| |
| TEST_F(DiskCacheBackendTest, Enumerations2) { |
| BackendEnumerations2(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionEnumerations2) { |
| SetNewEviction(); |
| BackendEnumerations2(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, MemoryOnlyEnumerations2) { |
| SetMemoryOnlyMode(); |
| BackendEnumerations2(); |
| } |
| |
| |
| // Verify handling of invalid entries while doing enumerations. |
| // We'll be leaking memory from this test. |
| void DiskCacheBackendTest::BackendInvalidEntryEnumeration() { |
| // Use the implementation directly... we need to simulate a crash. |
| SetDirectMode(); |
| InitCache(); |
| |
| std::string key("Some key"); |
| disk_cache::Entry *entry, *entry1, *entry2; |
| ASSERT_TRUE(cache_->CreateEntry(key, &entry1)); |
| |
| const int kSize = 50; |
| scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); |
| memset(buffer1->data(), 0, kSize); |
| base::strlcpy(buffer1->data(), "And the data to save", kSize); |
| EXPECT_EQ(kSize, entry1->WriteData(0, 0, buffer1, kSize, NULL, false)); |
| entry1->Close(); |
| ASSERT_TRUE(cache_->OpenEntry(key, &entry1)); |
| EXPECT_EQ(kSize, entry1->ReadData(0, 0, buffer1, kSize, NULL)); |
| |
| std::string key2("Another key"); |
| ASSERT_TRUE(cache_->CreateEntry(key2, &entry2)); |
| entry2->Close(); |
| ASSERT_EQ(2, cache_->GetEntryCount()); |
| |
| SimulateCrash(); |
| |
| void* iter = NULL; |
| int count = 0; |
| while (cache_->OpenNextEntry(&iter, &entry)) { |
| ASSERT_TRUE(NULL != entry); |
| EXPECT_EQ(key2, entry->GetKey()); |
| entry->Close(); |
| count++; |
| }; |
| EXPECT_EQ(1, count); |
| EXPECT_EQ(1, cache_->GetEntryCount()); |
| } |
| |
| // We'll be leaking memory from this test. |
| TEST_F(DiskCacheBackendTest, InvalidEntryEnumeration) { |
| BackendInvalidEntryEnumeration(); |
| } |
| |
| // We'll be leaking memory from this test. |
| TEST_F(DiskCacheBackendTest, NewEvictionInvalidEntryEnumeration) { |
| SetNewEviction(); |
| BackendInvalidEntryEnumeration(); |
| } |
| |
| // Tests that if for some reason entries are modified close to existing cache |
| // iterators, we don't generate fatal errors or reset the cache. |
| void DiskCacheBackendTest::BackendFixEnumerators() { |
| InitCache(); |
| |
| int seed = static_cast<int>(Time::Now().ToInternalValue()); |
| srand(seed); |
| |
| const int kNumEntries = 10; |
| for (int i = 0; i < kNumEntries; i++) { |
| std::string key = GenerateKey(true); |
| disk_cache::Entry* entry; |
| ASSERT_TRUE(cache_->CreateEntry(key, &entry)); |
| entry->Close(); |
| } |
| EXPECT_EQ(kNumEntries, cache_->GetEntryCount()); |
| |
| disk_cache::Entry *entry1, *entry2; |
| void* iter1 = NULL; |
| void* iter2 = NULL; |
| ASSERT_TRUE(cache_->OpenNextEntry(&iter1, &entry1)); |
| ASSERT_TRUE(NULL != entry1); |
| entry1->Close(); |
| entry1 = NULL; |
| |
| // Let's go to the middle of the list. |
| for (int i = 0; i < kNumEntries / 2; i++) { |
| if (entry1) |
| entry1->Close(); |
| ASSERT_TRUE(cache_->OpenNextEntry(&iter1, &entry1)); |
| ASSERT_TRUE(NULL != entry1); |
| |
| ASSERT_TRUE(cache_->OpenNextEntry(&iter2, &entry2)); |
| ASSERT_TRUE(NULL != entry2); |
| entry2->Close(); |
| } |
| |
| // Messing up with entry1 will modify entry2->next. |
| entry1->Doom(); |
| ASSERT_TRUE(cache_->OpenNextEntry(&iter2, &entry2)); |
| ASSERT_TRUE(NULL != entry2); |
| |
| // The link entry2->entry1 should be broken. |
| EXPECT_NE(entry2->GetKey(), entry1->GetKey()); |
| entry1->Close(); |
| entry2->Close(); |
| |
| // And the second iterator should keep working. |
| ASSERT_TRUE(cache_->OpenNextEntry(&iter2, &entry2)); |
| ASSERT_TRUE(NULL != entry2); |
| entry2->Close(); |
| |
| cache_->EndEnumeration(&iter1); |
| cache_->EndEnumeration(&iter2); |
| } |
| |
| TEST_F(DiskCacheBackendTest, FixEnumerators) { |
| BackendFixEnumerators(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionFixEnumerators) { |
| SetNewEviction(); |
| BackendFixEnumerators(); |
| } |
| |
| void DiskCacheBackendTest::BackendDoomRecent() { |
| InitCache(); |
| Time initial = Time::Now(); |
| |
| disk_cache::Entry *entry; |
| ASSERT_TRUE(cache_->CreateEntry("first", &entry)); |
| entry->Close(); |
| ASSERT_TRUE(cache_->CreateEntry("second", &entry)); |
| entry->Close(); |
| |
| PlatformThread::Sleep(20); |
| Time middle = Time::Now(); |
| |
| ASSERT_TRUE(cache_->CreateEntry("third", &entry)); |
| entry->Close(); |
| ASSERT_TRUE(cache_->CreateEntry("fourth", &entry)); |
| entry->Close(); |
| |
| PlatformThread::Sleep(20); |
| Time final = Time::Now(); |
| |
| ASSERT_EQ(4, cache_->GetEntryCount()); |
| EXPECT_TRUE(cache_->DoomEntriesSince(final)); |
| ASSERT_EQ(4, cache_->GetEntryCount()); |
| |
| EXPECT_TRUE(cache_->DoomEntriesSince(middle)); |
| ASSERT_EQ(2, cache_->GetEntryCount()); |
| |
| ASSERT_TRUE(cache_->OpenEntry("second", &entry)); |
| entry->Close(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, DoomRecent) { |
| BackendDoomRecent(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionDoomRecent) { |
| SetNewEviction(); |
| BackendDoomRecent(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, MemoryOnlyDoomRecent) { |
| SetMemoryOnlyMode(); |
| BackendDoomRecent(); |
| } |
| |
| void DiskCacheBackendTest::BackendDoomBetween() { |
| InitCache(); |
| Time initial = Time::Now(); |
| |
| disk_cache::Entry *entry; |
| ASSERT_TRUE(cache_->CreateEntry("first", &entry)); |
| entry->Close(); |
| |
| PlatformThread::Sleep(20); |
| Time middle_start = Time::Now(); |
| |
| ASSERT_TRUE(cache_->CreateEntry("second", &entry)); |
| entry->Close(); |
| ASSERT_TRUE(cache_->CreateEntry("third", &entry)); |
| entry->Close(); |
| |
| PlatformThread::Sleep(20); |
| Time middle_end = Time::Now(); |
| |
| ASSERT_TRUE(cache_->CreateEntry("fourth", &entry)); |
| entry->Close(); |
| ASSERT_TRUE(cache_->OpenEntry("fourth", &entry)); |
| entry->Close(); |
| |
| PlatformThread::Sleep(20); |
| Time final = Time::Now(); |
| |
| ASSERT_EQ(4, cache_->GetEntryCount()); |
| EXPECT_TRUE(cache_->DoomEntriesBetween(middle_start, middle_end)); |
| ASSERT_EQ(2, cache_->GetEntryCount()); |
| |
| ASSERT_TRUE(cache_->OpenEntry("fourth", &entry)); |
| entry->Close(); |
| |
| EXPECT_TRUE(cache_->DoomEntriesBetween(middle_start, final)); |
| ASSERT_EQ(1, cache_->GetEntryCount()); |
| |
| ASSERT_TRUE(cache_->OpenEntry("first", &entry)); |
| entry->Close(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, DoomBetween) { |
| BackendDoomBetween(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionDoomBetween) { |
| SetNewEviction(); |
| BackendDoomBetween(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, MemoryOnlyDoomBetween) { |
| SetMemoryOnlyMode(); |
| BackendDoomBetween(); |
| } |
| |
| void DiskCacheBackendTest::BackendTransaction(const std::wstring& name, |
| int num_entries, bool load) { |
| success_ = false; |
| ASSERT_TRUE(CopyTestCache(name)); |
| DisableFirstCleanup(); |
| |
| if (load) { |
| SetMask(0xf); |
| SetMaxSize(0x100000); |
| } else { |
| // Clear the settings from the previous run. |
| SetMask(0); |
| SetMaxSize(0); |
| } |
| |
| InitCache(); |
| ASSERT_EQ(num_entries + 1, cache_->GetEntryCount()); |
| |
| std::string key("the first key"); |
| disk_cache::Entry* entry1; |
| ASSERT_FALSE(cache_->OpenEntry(key, &entry1)); |
| |
| int actual = cache_->GetEntryCount(); |
| if (num_entries != actual) { |
| ASSERT_TRUE(load); |
| // If there is a heavy load, inserting an entry will make another entry |
| // dirty (on the hash bucket) so two entries are removed. |
| ASSERT_EQ(num_entries - 1, actual); |
| } |
| |
| delete cache_; |
| cache_ = NULL; |
| cache_impl_ = NULL; |
| |
| ASSERT_TRUE(CheckCacheIntegrity(GetCacheFilePath(), new_eviction_)); |
| success_ = true; |
| } |
| |
| void DiskCacheBackendTest::BackendRecoverInsert() { |
| // Tests with an empty cache. |
| BackendTransaction(L"insert_empty1", 0, false); |
| ASSERT_TRUE(success_) << "insert_empty1"; |
| BackendTransaction(L"insert_empty2", 0, false); |
| ASSERT_TRUE(success_) << "insert_empty2"; |
| BackendTransaction(L"insert_empty3", 0, false); |
| ASSERT_TRUE(success_) << "insert_empty3"; |
| |
| // Tests with one entry on the cache. |
| BackendTransaction(L"insert_one1", 1, false); |
| ASSERT_TRUE(success_) << "insert_one1"; |
| BackendTransaction(L"insert_one2", 1, false); |
| ASSERT_TRUE(success_) << "insert_one2"; |
| BackendTransaction(L"insert_one3", 1, false); |
| ASSERT_TRUE(success_) << "insert_one3"; |
| |
| // Tests with one hundred entries on the cache, tiny index. |
| BackendTransaction(L"insert_load1", 100, true); |
| ASSERT_TRUE(success_) << "insert_load1"; |
| BackendTransaction(L"insert_load2", 100, true); |
| ASSERT_TRUE(success_) << "insert_load2"; |
| } |
| |
| TEST_F(DiskCacheBackendTest, RecoverInsert) { |
| BackendRecoverInsert(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionRecoverInsert) { |
| SetNewEviction(); |
| BackendRecoverInsert(); |
| } |
| |
| void DiskCacheBackendTest::BackendRecoverRemove() { |
| // Removing the only element. |
| BackendTransaction(L"remove_one1", 0, false); |
| ASSERT_TRUE(success_) << "remove_one1"; |
| BackendTransaction(L"remove_one2", 0, false); |
| ASSERT_TRUE(success_) << "remove_one2"; |
| BackendTransaction(L"remove_one3", 0, false); |
| ASSERT_TRUE(success_) << "remove_one3"; |
| |
| // Removing the head. |
| BackendTransaction(L"remove_head1", 1, false); |
| ASSERT_TRUE(success_) << "remove_head1"; |
| BackendTransaction(L"remove_head2", 1, false); |
| ASSERT_TRUE(success_) << "remove_head2"; |
| BackendTransaction(L"remove_head3", 1, false); |
| ASSERT_TRUE(success_) << "remove_head3"; |
| |
| // Removing the tail. |
| BackendTransaction(L"remove_tail1", 1, false); |
| ASSERT_TRUE(success_) << "remove_tail1"; |
| BackendTransaction(L"remove_tail2", 1, false); |
| ASSERT_TRUE(success_) << "remove_tail2"; |
| BackendTransaction(L"remove_tail3", 1, false); |
| ASSERT_TRUE(success_) << "remove_tail3"; |
| |
| // Removing with one hundred entries on the cache, tiny index. |
| BackendTransaction(L"remove_load1", 100, true); |
| ASSERT_TRUE(success_) << "remove_load1"; |
| BackendTransaction(L"remove_load2", 100, true); |
| ASSERT_TRUE(success_) << "remove_load2"; |
| BackendTransaction(L"remove_load3", 100, true); |
| ASSERT_TRUE(success_) << "remove_load3"; |
| |
| #ifdef NDEBUG |
| // This case cannot be reverted, so it will assert on debug builds. |
| BackendTransaction(L"remove_one4", 0, false); |
| ASSERT_TRUE(success_) << "remove_one4"; |
| BackendTransaction(L"remove_head4", 1, false); |
| ASSERT_TRUE(success_) << "remove_head4"; |
| #endif |
| } |
| |
| TEST_F(DiskCacheBackendTest, RecoverRemove) { |
| BackendRecoverRemove(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionRecoverRemove) { |
| SetNewEviction(); |
| BackendRecoverRemove(); |
| } |
| |
| // Tests dealing with cache files that cannot be recovered. |
| TEST_F(DiskCacheTest, Backend_DeleteOld) { |
| ASSERT_TRUE(CopyTestCache(L"wrong_version")); |
| FilePath path = GetCacheFilePath(); |
| scoped_ptr<disk_cache::Backend> cache; |
| cache.reset(disk_cache::CreateCacheBackend(path, true, 0, net::DISK_CACHE)); |
| |
| MessageLoopHelper helper; |
| |
| ASSERT_TRUE(NULL != cache.get()); |
| ASSERT_EQ(0, cache->GetEntryCount()); |
| |
| // Wait for a callback that never comes... about 2 secs :). The message loop |
| // has to run to allow destruction of the cleaner thread. |
| helper.WaitUntilCacheIoFinished(1); |
| } |
| |
| // We want to be able to deal with messed up entries on disk. |
| void DiskCacheBackendTest::BackendInvalidEntry2() { |
| ASSERT_TRUE(CopyTestCache(L"bad_entry")); |
| DisableFirstCleanup(); |
| InitCache(); |
| |
| disk_cache::Entry *entry1, *entry2; |
| ASSERT_TRUE(cache_->OpenEntry("the first key", &entry1)); |
| EXPECT_FALSE(cache_->OpenEntry("some other key", &entry2)); |
| entry1->Close(); |
| |
| // CheckCacheIntegrity will fail at this point. |
| DisableIntegrityCheck(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, InvalidEntry2) { |
| BackendInvalidEntry2(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionInvalidEntry2) { |
| SetNewEviction(); |
| BackendInvalidEntry2(); |
| } |
| |
| // We want to be able to deal with abnormal dirty entries. |
| void DiskCacheBackendTest::BackendNotMarkedButDirty(const std::wstring& name) { |
| ASSERT_TRUE(CopyTestCache(name)); |
| DisableFirstCleanup(); |
| InitCache(); |
| |
| disk_cache::Entry *entry1, *entry2; |
| ASSERT_TRUE(cache_->OpenEntry("the first key", &entry1)); |
| EXPECT_FALSE(cache_->OpenEntry("some other key", &entry2)); |
| entry1->Close(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NotMarkedButDirty) { |
| BackendNotMarkedButDirty(L"dirty_entry"); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionNotMarkedButDirty) { |
| SetNewEviction(); |
| BackendNotMarkedButDirty(L"dirty_entry"); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NotMarkedButDirty2) { |
| BackendNotMarkedButDirty(L"dirty_entry2"); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionNotMarkedButDirty2) { |
| SetNewEviction(); |
| BackendNotMarkedButDirty(L"dirty_entry2"); |
| } |
| |
| // We want to be able to deal with messed up entries on disk. |
| void DiskCacheBackendTest::BackendInvalidRankings2() { |
| ASSERT_TRUE(CopyTestCache(L"bad_rankings")); |
| FilePath path = GetCacheFilePath(); |
| DisableFirstCleanup(); |
| InitCache(); |
| |
| disk_cache::Entry *entry1, *entry2; |
| EXPECT_FALSE(cache_->OpenEntry("the first key", &entry1)); |
| ASSERT_TRUE(cache_->OpenEntry("some other key", &entry2)); |
| entry2->Close(); |
| |
| // CheckCacheIntegrity will fail at this point. |
| DisableIntegrityCheck(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, InvalidRankings2) { |
| BackendInvalidRankings2(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionInvalidRankings2) { |
| SetNewEviction(); |
| BackendInvalidRankings2(); |
| } |
| |
| // If the LRU is corrupt, we delete the cache. |
| void DiskCacheBackendTest::BackendInvalidRankings() { |
| disk_cache::Entry* entry; |
| void* iter = NULL; |
| ASSERT_TRUE(cache_->OpenNextEntry(&iter, &entry)); |
| entry->Close(); |
| EXPECT_EQ(2, cache_->GetEntryCount()); |
| |
| EXPECT_FALSE(cache_->OpenNextEntry(&iter, &entry)); |
| MessageLoop::current()->RunAllPending(); |
| EXPECT_EQ(0, cache_->GetEntryCount()); |
| } |
| |
| TEST_F(DiskCacheBackendTest, InvalidRankingsSuccess) { |
| ASSERT_TRUE(CopyTestCache(L"bad_rankings")); |
| DisableFirstCleanup(); |
| SetDirectMode(); |
| InitCache(); |
| BackendInvalidRankings(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionInvalidRankingsSuccess) { |
| ASSERT_TRUE(CopyTestCache(L"bad_rankings")); |
| DisableFirstCleanup(); |
| SetDirectMode(); |
| SetNewEviction(); |
| InitCache(); |
| BackendInvalidRankings(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, InvalidRankingsFailure) { |
| ASSERT_TRUE(CopyTestCache(L"bad_rankings")); |
| DisableFirstCleanup(); |
| SetDirectMode(); |
| InitCache(); |
| SetTestMode(); // Fail cache reinitialization. |
| BackendInvalidRankings(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionInvalidRankingsFailure) { |
| ASSERT_TRUE(CopyTestCache(L"bad_rankings")); |
| DisableFirstCleanup(); |
| SetDirectMode(); |
| SetNewEviction(); |
| InitCache(); |
| SetTestMode(); // Fail cache reinitialization. |
| BackendInvalidRankings(); |
| } |
| |
| // If the LRU is corrupt and we have open entries, we disable the cache. |
| void DiskCacheBackendTest::BackendDisable() { |
| disk_cache::Entry *entry1, *entry2; |
| void* iter = NULL; |
| ASSERT_TRUE(cache_->OpenNextEntry(&iter, &entry1)); |
| |
| EXPECT_FALSE(cache_->OpenNextEntry(&iter, &entry2)); |
| EXPECT_EQ(2, cache_->GetEntryCount()); |
| EXPECT_FALSE(cache_->CreateEntry("Something new", &entry2)); |
| |
| entry1->Close(); |
| MessageLoop::current()->RunAllPending(); |
| |
| EXPECT_EQ(0, cache_->GetEntryCount()); |
| } |
| |
| TEST_F(DiskCacheBackendTest, DisableSuccess) { |
| ASSERT_TRUE(CopyTestCache(L"bad_rankings")); |
| DisableFirstCleanup(); |
| SetDirectMode(); |
| InitCache(); |
| BackendDisable(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionDisableSuccess) { |
| ASSERT_TRUE(CopyTestCache(L"bad_rankings")); |
| DisableFirstCleanup(); |
| SetDirectMode(); |
| SetNewEviction(); |
| InitCache(); |
| BackendDisable(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, DisableFailure) { |
| ASSERT_TRUE(CopyTestCache(L"bad_rankings")); |
| DisableFirstCleanup(); |
| SetDirectMode(); |
| InitCache(); |
| SetTestMode(); // Fail cache reinitialization. |
| BackendDisable(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionDisableFailure) { |
| ASSERT_TRUE(CopyTestCache(L"bad_rankings")); |
| DisableFirstCleanup(); |
| SetDirectMode(); |
| SetNewEviction(); |
| InitCache(); |
| SetTestMode(); // Fail cache reinitialization. |
| BackendDisable(); |
| } |
| |
| // This is another type of corruption on the LRU; disable the cache. |
| void DiskCacheBackendTest::BackendDisable2() { |
| EXPECT_EQ(8, cache_->GetEntryCount()); |
| |
| disk_cache::Entry* entry; |
| void* iter = NULL; |
| int count = 0; |
| while (cache_->OpenNextEntry(&iter, &entry)) { |
| ASSERT_TRUE(NULL != entry); |
| entry->Close(); |
| count++; |
| ASSERT_LT(count, 9); |
| }; |
| |
| MessageLoop::current()->RunAllPending(); |
| EXPECT_EQ(0, cache_->GetEntryCount()); |
| } |
| |
| TEST_F(DiskCacheBackendTest, DisableSuccess2) { |
| ASSERT_TRUE(CopyTestCache(L"list_loop")); |
| DisableFirstCleanup(); |
| SetDirectMode(); |
| InitCache(); |
| BackendDisable2(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionDisableSuccess2) { |
| ASSERT_TRUE(CopyTestCache(L"list_loop")); |
| DisableFirstCleanup(); |
| SetNewEviction(); |
| SetDirectMode(); |
| InitCache(); |
| BackendDisable2(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, DisableFailure2) { |
| ASSERT_TRUE(CopyTestCache(L"list_loop")); |
| DisableFirstCleanup(); |
| SetDirectMode(); |
| InitCache(); |
| SetTestMode(); // Fail cache reinitialization. |
| BackendDisable2(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionDisableFailure2) { |
| ASSERT_TRUE(CopyTestCache(L"list_loop")); |
| DisableFirstCleanup(); |
| SetDirectMode(); |
| SetNewEviction(); |
| InitCache(); |
| SetTestMode(); // Fail cache reinitialization. |
| BackendDisable2(); |
| } |
| |
| // If the index size changes when we disable the cache, we should not crash. |
| void DiskCacheBackendTest::BackendDisable3() { |
| disk_cache::Entry *entry1, *entry2; |
| void* iter = NULL; |
| EXPECT_EQ(2, cache_->GetEntryCount()); |
| ASSERT_TRUE(cache_->OpenNextEntry(&iter, &entry1)); |
| entry1->Close(); |
| |
| EXPECT_FALSE(cache_->OpenNextEntry(&iter, &entry2)); |
| MessageLoop::current()->RunAllPending(); |
| |
| ASSERT_TRUE(cache_->CreateEntry("Something new", &entry2)); |
| entry2->Close(); |
| |
| EXPECT_EQ(1, cache_->GetEntryCount()); |
| } |
| |
| TEST_F(DiskCacheBackendTest, DisableSuccess3) { |
| ASSERT_TRUE(CopyTestCache(L"bad_rankings2")); |
| DisableFirstCleanup(); |
| SetMaxSize(20 * 1024 * 1024); |
| InitCache(); |
| BackendDisable3(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionDisableSuccess3) { |
| ASSERT_TRUE(CopyTestCache(L"bad_rankings2")); |
| DisableFirstCleanup(); |
| SetMaxSize(20 * 1024 * 1024); |
| SetNewEviction(); |
| InitCache(); |
| BackendDisable3(); |
| } |
| |
| // If we disable the cache, already open entries should work as far as possible. |
| void DiskCacheBackendTest::BackendDisable4() { |
| disk_cache::Entry *entry1, *entry2, *entry3, *entry4; |
| void* iter = NULL; |
| ASSERT_TRUE(cache_->OpenNextEntry(&iter, &entry1)); |
| |
| char key2[2000]; |
| char key3[20000]; |
| CacheTestFillBuffer(key2, sizeof(key2), true); |
| CacheTestFillBuffer(key3, sizeof(key3), true); |
| key2[sizeof(key2) - 1] = '\0'; |
| key3[sizeof(key3) - 1] = '\0'; |
| ASSERT_TRUE(cache_->CreateEntry(key2, &entry2)); |
| ASSERT_TRUE(cache_->CreateEntry(key3, &entry3)); |
| |
| const int kBufSize = 20000; |
| scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kBufSize); |
| memset(buf->data(), 0, kBufSize); |
| EXPECT_EQ(100, entry2->WriteData(0, 0, buf, 100, NULL, false)); |
| EXPECT_EQ(kBufSize, entry3->WriteData(0, 0, buf, kBufSize, NULL, false)); |
| |
| // This line should disable the cache but not delete it. |
| EXPECT_FALSE(cache_->OpenNextEntry(&iter, &entry4)); |
| EXPECT_EQ(4, cache_->GetEntryCount()); |
| |
| EXPECT_FALSE(cache_->CreateEntry("cache is disabled", &entry4)); |
| |
| EXPECT_EQ(100, entry2->ReadData(0, 0, buf, 100, NULL)); |
| EXPECT_EQ(100, entry2->WriteData(0, 0, buf, 100, NULL, false)); |
| EXPECT_EQ(100, entry2->WriteData(1, 0, buf, 100, NULL, false)); |
| |
| EXPECT_EQ(kBufSize, entry3->ReadData(0, 0, buf, kBufSize, NULL)); |
| EXPECT_EQ(kBufSize, entry3->WriteData(0, 0, buf, kBufSize, NULL, false)); |
| EXPECT_EQ(kBufSize, entry3->WriteData(1, 0, buf, kBufSize, NULL, false)); |
| |
| std::string key = entry2->GetKey(); |
| EXPECT_EQ(sizeof(key2) - 1, key.size()); |
| key = entry3->GetKey(); |
| EXPECT_EQ(sizeof(key3) - 1, key.size()); |
| |
| entry1->Close(); |
| entry2->Close(); |
| entry3->Close(); |
| MessageLoop::current()->RunAllPending(); |
| |
| EXPECT_EQ(0, cache_->GetEntryCount()); |
| } |
| |
| TEST_F(DiskCacheBackendTest, DisableSuccess4) { |
| ASSERT_TRUE(CopyTestCache(L"bad_rankings")); |
| DisableFirstCleanup(); |
| SetDirectMode(); |
| InitCache(); |
| BackendDisable4(); |
| } |
| |
| // Flaky, http://crbug.com/21110. |
| // TODO(rvargas): Add more debugging code to help identify the root cause. |
| TEST_F(DiskCacheBackendTest, FLAKY_NewEvictionDisableSuccess4) { |
| ASSERT_TRUE(CopyTestCache(L"bad_rankings")); |
| DisableFirstCleanup(); |
| SetDirectMode(); |
| SetNewEviction(); |
| InitCache(); |
| BackendDisable4(); |
| } |
| |
| TEST_F(DiskCacheTest, Backend_UsageStats) { |
| MessageLoopHelper helper; |
| |
| FilePath path = GetCacheFilePath(); |
| ASSERT_TRUE(DeleteCache(path)); |
| scoped_ptr<disk_cache::BackendImpl> cache; |
| cache.reset(new disk_cache::BackendImpl(path)); |
| ASSERT_TRUE(NULL != cache.get()); |
| cache->SetUnitTestMode(); |
| ASSERT_TRUE(cache->Init()); |
| |
| // Wait for a callback that never comes... about 2 secs :). The message loop |
| // has to run to allow invocation of the usage timer. |
| helper.WaitUntilCacheIoFinished(1); |
| } |
| |
| void DiskCacheBackendTest::BackendDoomAll() { |
| InitCache(); |
| Time initial = Time::Now(); |
| |
| disk_cache::Entry *entry1, *entry2; |
| ASSERT_TRUE(cache_->CreateEntry("first", &entry1)); |
| ASSERT_TRUE(cache_->CreateEntry("second", &entry2)); |
| entry1->Close(); |
| entry2->Close(); |
| |
| ASSERT_TRUE(cache_->CreateEntry("third", &entry1)); |
| ASSERT_TRUE(cache_->CreateEntry("fourth", &entry2)); |
| |
| ASSERT_EQ(4, cache_->GetEntryCount()); |
| EXPECT_TRUE(cache_->DoomAllEntries()); |
| ASSERT_EQ(0, cache_->GetEntryCount()); |
| |
| disk_cache::Entry *entry3, *entry4; |
| ASSERT_TRUE(cache_->CreateEntry("third", &entry3)); |
| ASSERT_TRUE(cache_->CreateEntry("fourth", &entry4)); |
| |
| EXPECT_TRUE(cache_->DoomAllEntries()); |
| ASSERT_EQ(0, cache_->GetEntryCount()); |
| |
| entry1->Close(); |
| entry2->Close(); |
| entry3->Doom(); // The entry should be already doomed, but this must work. |
| entry3->Close(); |
| entry4->Close(); |
| |
| // Now try with all references released. |
| ASSERT_TRUE(cache_->CreateEntry("third", &entry1)); |
| ASSERT_TRUE(cache_->CreateEntry("fourth", &entry2)); |
| entry1->Close(); |
| entry2->Close(); |
| |
| ASSERT_EQ(2, cache_->GetEntryCount()); |
| EXPECT_TRUE(cache_->DoomAllEntries()); |
| ASSERT_EQ(0, cache_->GetEntryCount()); |
| } |
| |
| TEST_F(DiskCacheBackendTest, DoomAll) { |
| BackendDoomAll(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionDoomAll) { |
| SetNewEviction(); |
| BackendDoomAll(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, MemoryOnlyDoomAll) { |
| SetMemoryOnlyMode(); |
| BackendDoomAll(); |
| } |
| |
| // If the index size changes when we doom the cache, we should not crash. |
| void DiskCacheBackendTest::BackendDoomAll2() { |
| EXPECT_EQ(2, cache_->GetEntryCount()); |
| EXPECT_TRUE(cache_->DoomAllEntries()); |
| |
| disk_cache::Entry* entry; |
| ASSERT_TRUE(cache_->CreateEntry("Something new", &entry)); |
| entry->Close(); |
| |
| EXPECT_EQ(1, cache_->GetEntryCount()); |
| } |
| |
| TEST_F(DiskCacheBackendTest, DoomAll2) { |
| ASSERT_TRUE(CopyTestCache(L"bad_rankings2")); |
| DisableFirstCleanup(); |
| SetMaxSize(20 * 1024 * 1024); |
| InitCache(); |
| BackendDoomAll2(); |
| } |
| |
| TEST_F(DiskCacheBackendTest, NewEvictionDoomAll2) { |
| ASSERT_TRUE(CopyTestCache(L"bad_rankings2")); |
| DisableFirstCleanup(); |
| SetMaxSize(20 * 1024 * 1024); |
| SetNewEviction(); |
| InitCache(); |
| BackendDoomAll2(); |
| } |
| |
| // We should be able to create the same entry on multiple simultaneous instances |
| // of the cache. |
| TEST_F(DiskCacheTest, MultipleInstances) { |
| ScopedTestCache store1; |
| ScopedTestCache store2("cache_test2"); |
| ScopedTestCache store3("cache_test3"); |
| |
| const int kNumberOfCaches = 2; |
| scoped_ptr<disk_cache::Backend> cache[kNumberOfCaches]; |
| |
| cache[0].reset(disk_cache::CreateCacheBackend(store1.path(), false, 0, |
| net::DISK_CACHE)); |
| cache[1].reset(disk_cache::CreateCacheBackend(store2.path(), false, 0, |
| net::MEDIA_CACHE)); |
| |
| ASSERT_TRUE(cache[0].get() != NULL && cache[1].get() != NULL); |
| |
| std::string key("the first key"); |
| disk_cache::Entry* entry; |
| for (int i = 0; i < kNumberOfCaches; i++) { |
| ASSERT_TRUE(cache[i]->CreateEntry(key, &entry)); |
| entry->Close(); |
| } |
| } |
| |
| // Test the four regions of the curve that determines the max cache size. |
| TEST_F(DiskCacheTest, AutomaticMaxSize) { |
| const int kDefaultSize = 80 * 1024 * 1024; |
| int64 large_size = kDefaultSize; |
| |
| EXPECT_EQ(kDefaultSize, disk_cache::PreferedCacheSize(large_size)); |
| EXPECT_EQ((kDefaultSize / 2) * 8 / 10, |
| disk_cache::PreferedCacheSize(large_size / 2)); |
| |
| EXPECT_EQ(kDefaultSize, disk_cache::PreferedCacheSize(large_size * 2)); |
| EXPECT_EQ(kDefaultSize, disk_cache::PreferedCacheSize(large_size * 4)); |
| EXPECT_EQ(kDefaultSize, disk_cache::PreferedCacheSize(large_size * 10)); |
| |
| EXPECT_EQ(kDefaultSize * 2, disk_cache::PreferedCacheSize(large_size * 20)); |
| EXPECT_EQ(kDefaultSize * 5 / 2, |
| disk_cache::PreferedCacheSize(large_size * 50 / 2)); |
| |
| EXPECT_EQ(kDefaultSize * 5 / 2, |
| disk_cache::PreferedCacheSize(large_size * 51 / 2)); |
| EXPECT_EQ(kDefaultSize * 5 / 2, |
| disk_cache::PreferedCacheSize(large_size * 100 / 2)); |
| EXPECT_EQ(kDefaultSize * 5 / 2, |
| disk_cache::PreferedCacheSize(large_size * 500 / 2)); |
| |
| EXPECT_EQ(kDefaultSize * 6 / 2, |
| disk_cache::PreferedCacheSize(large_size * 600 / 2)); |
| EXPECT_EQ(kDefaultSize * 7 / 2, |
| disk_cache::PreferedCacheSize(large_size * 700 / 2)); |
| } |