diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 22:42:52 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 22:42:52 +0000 |
commit | 586acc5fe142f498261f52c66862fa417c3d52d2 (patch) | |
tree | c98b3417a883f2477029c8cd5888f4078681e24e /net/disk_cache/entry_unittest.cc | |
parent | a814a8d55429605fe6d7045045cd25b6bf624580 (diff) | |
download | chromium_src-586acc5fe142f498261f52c66862fa417c3d52d2.zip chromium_src-586acc5fe142f498261f52c66862fa417c3d52d2.tar.gz chromium_src-586acc5fe142f498261f52c66862fa417c3d52d2.tar.bz2 |
Add net to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/disk_cache/entry_unittest.cc')
-rw-r--r-- | net/disk_cache/entry_unittest.cc | 713 |
1 files changed, 713 insertions, 0 deletions
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc new file mode 100644 index 0000000..d2eea79 --- /dev/null +++ b/net/disk_cache/entry_unittest.cc @@ -0,0 +1,713 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "base/timer.h" +#include "net/base/net_errors.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 "testing/gtest/include/gtest/gtest.h" + +extern int g_cache_tests_max_id; +extern volatile int g_cache_tests_received; +extern volatile bool g_cache_tests_error; + +// Tests that can run with different types of caches. +class DiskCacheEntryTest : public DiskCacheTestBase { + protected: + void InternalSyncIO(); + void InternalAsyncIO(); + void ExternalSyncIO(); + void ExternalAsyncIO(); + void GetKey(); + void GrowData(); + void TruncateData(); + void InvalidData(); + void DoomEntry(); + void DoomedEntry(); +}; + +void DiskCacheEntryTest::InternalSyncIO() { + disk_cache::Entry *entry1 = NULL; + ASSERT_TRUE(cache_->CreateEntry("the first key", &entry1)); + ASSERT_TRUE(NULL != entry1); + + char buffer1[10]; + CacheTestFillBuffer(buffer1, sizeof(buffer1), false); + EXPECT_EQ(0, entry1->ReadData(0, 0, buffer1, sizeof(buffer1), NULL)); + strcpy_s(buffer1, "the data"); + EXPECT_EQ(10, entry1->WriteData(0, 0, buffer1, sizeof(buffer1), NULL, false)); + memset(buffer1, 0, sizeof(buffer1)); + EXPECT_EQ(10, entry1->ReadData(0, 0, buffer1, sizeof(buffer1), NULL)); + EXPECT_STREQ("the data", buffer1); + + char buffer2[5000]; + char buffer3[10000] = {0}; + CacheTestFillBuffer(buffer2, sizeof(buffer2), false); + strcpy_s(buffer2, "The really big data goes here"); + EXPECT_EQ(5000, entry1->WriteData(1, 1500, buffer2, sizeof(buffer2), NULL, + false)); + memset(buffer2, 0, sizeof(buffer2)); + EXPECT_EQ(4989, entry1->ReadData(1, 1511, buffer2, sizeof(buffer2), NULL)); + EXPECT_STREQ("big data goes here", buffer2); + EXPECT_EQ(5000, entry1->ReadData(1, 0, buffer2, sizeof(buffer2), NULL)); + EXPECT_EQ(0, memcmp(buffer2, buffer3, 1500)); + EXPECT_EQ(1500, entry1->ReadData(1, 5000, buffer2, sizeof(buffer2), NULL)); + + EXPECT_EQ(0, entry1->ReadData(1, 6500, buffer2, sizeof(buffer2), NULL)); + EXPECT_EQ(6500, entry1->ReadData(1, 0, buffer3, sizeof(buffer3), NULL)); + EXPECT_EQ(8192, entry1->WriteData(1, 0, buffer3, 8192, NULL, false)); + EXPECT_EQ(8192, entry1->ReadData(1, 0, buffer3, sizeof(buffer3), NULL)); + EXPECT_EQ(8192, entry1->GetDataSize(1)); + + entry1->Doom(); + entry1->Close(); + EXPECT_EQ(0, cache_->GetEntryCount()); +} + +TEST_F(DiskCacheEntryTest, InternalSyncIO) { + InitCache(); + InternalSyncIO(); +} + +TEST_F(DiskCacheEntryTest, MemoryOnlyInternalSyncIO) { + SetMemoryOnlyMode(); + InitCache(); + InternalSyncIO(); +} + +void DiskCacheEntryTest::InternalAsyncIO() { + disk_cache::Entry *entry1 = NULL; + ASSERT_TRUE(cache_->CreateEntry("the first key", &entry1)); + ASSERT_TRUE(NULL != entry1); + + // Let's verify that each IO goes to the right callback object. + CallbackTest callback1(1, false); + CallbackTest callback2(2, false); + CallbackTest callback3(3, false); + CallbackTest callback4(4, false); + CallbackTest callback5(5, false); + CallbackTest callback6(6, false); + CallbackTest callback7(7, false); + CallbackTest callback8(8, false); + CallbackTest callback9(9, false); + CallbackTest callback10(10, false); + CallbackTest callback11(11, false); + CallbackTest callback12(12, false); + CallbackTest callback13(13, false); + + g_cache_tests_error = false; + g_cache_tests_max_id = 0; + g_cache_tests_received = 0; + + MessageLoopHelper helper; + + char buffer1[10]; + char buffer2[5000]; + char buffer3[10000]; + CacheTestFillBuffer(buffer1, sizeof(buffer1), false); + CacheTestFillBuffer(buffer2, sizeof(buffer2), false); + CacheTestFillBuffer(buffer3, sizeof(buffer3), false); + + EXPECT_EQ(0, entry1->ReadData(0, 0, buffer1, sizeof(buffer1), &callback1)); + strcpy_s(buffer1, "the data"); + int expected = 0; + int ret = entry1->WriteData(0, 0, buffer1, sizeof(buffer1), &callback2, + false); + EXPECT_TRUE(10 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + memset(buffer2, 0, sizeof(buffer1)); + ret = entry1->ReadData(0, 0, buffer2, sizeof(buffer1), &callback3); + EXPECT_TRUE(10 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + g_cache_tests_max_id = 3; + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + EXPECT_STREQ("the data", buffer2); + + strcpy_s(buffer2, sizeof(buffer2), "The really big data goes here"); + ret = entry1->WriteData(1, 1500, buffer2, sizeof(buffer2), &callback4, false); + EXPECT_TRUE(5000 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + memset(buffer3, 0, sizeof(buffer2)); + ret = entry1->ReadData(1, 1511, buffer3, sizeof(buffer2), &callback5); + EXPECT_TRUE(4989 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + g_cache_tests_max_id = 5; + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + EXPECT_STREQ("big data goes here", buffer3); + ret = entry1->ReadData(1, 0, buffer2, sizeof(buffer2), &callback6); + EXPECT_TRUE(5000 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + memset(buffer3, 0, sizeof(buffer3)); + + g_cache_tests_max_id = 6; + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + EXPECT_EQ(0, memcmp(buffer2, buffer3, 1500)); + ret = entry1->ReadData(1, 5000, buffer2, sizeof(buffer2), &callback7); + EXPECT_TRUE(1500 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + EXPECT_EQ(0, entry1->ReadData(1, 6500, buffer2, sizeof(buffer2), &callback8)); + ret = entry1->ReadData(1, 0, buffer3, sizeof(buffer3), &callback9); + EXPECT_TRUE(6500 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + ret = entry1->WriteData(1, 0, buffer3, 8192, &callback10, false); + EXPECT_TRUE(8192 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + ret = entry1->ReadData(1, 0, buffer3, sizeof(buffer3), &callback11); + EXPECT_TRUE(8192 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + EXPECT_EQ(8192, entry1->GetDataSize(1)); + + ret = entry1->ReadData(0, 0, buffer1, sizeof(buffer1), &callback12); + EXPECT_TRUE(10 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + ret = entry1->ReadData(1, 0, buffer2, sizeof(buffer2), &callback13); + EXPECT_TRUE(5000 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + g_cache_tests_max_id = 13; + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + + EXPECT_FALSE(g_cache_tests_error); + EXPECT_EQ(expected, g_cache_tests_received); + + entry1->Doom(); + entry1->Close(); + EXPECT_EQ(0, cache_->GetEntryCount()); +} + +TEST_F(DiskCacheEntryTest, InternalAsyncIO) { + InitCache(); + InternalAsyncIO(); +} + +TEST_F(DiskCacheEntryTest, MemoryOnlyInternalAsyncIO) { + SetMemoryOnlyMode(); + InitCache(); + InternalAsyncIO(); +} + +void DiskCacheEntryTest::ExternalSyncIO() { + disk_cache::Entry *entry1; + ASSERT_TRUE(cache_->CreateEntry("the first key", &entry1)); + + char buffer1[17000], buffer2[25000]; + CacheTestFillBuffer(buffer1, sizeof(buffer1), false); + CacheTestFillBuffer(buffer2, sizeof(buffer2), false); + strcpy_s(buffer1, "the data"); + EXPECT_EQ(17000, entry1->WriteData(0, 0, buffer1, sizeof(buffer1), NULL, + false)); + memset(buffer1, 0, sizeof(buffer1)); + EXPECT_EQ(17000, entry1->ReadData(0, 0, buffer1, sizeof(buffer1), NULL)); + EXPECT_STREQ("the data", buffer1); + + strcpy_s(buffer2, "The really big data goes here"); + EXPECT_EQ(25000, entry1->WriteData(1, 10000, buffer2, sizeof(buffer2), NULL, + false)); + memset(buffer2, 0, sizeof(buffer2)); + EXPECT_EQ(24989, entry1->ReadData(1, 10011, buffer2, sizeof(buffer2), NULL)); + EXPECT_STREQ("big data goes here", buffer2); + EXPECT_EQ(25000, entry1->ReadData(1, 0, buffer2, sizeof(buffer2), NULL)); + EXPECT_EQ(0, memcmp(buffer2, buffer2, 10000)); + EXPECT_EQ(5000, entry1->ReadData(1, 30000, buffer2, sizeof(buffer2), NULL)); + + EXPECT_EQ(0, entry1->ReadData(1, 35000, buffer2, sizeof(buffer2), NULL)); + EXPECT_EQ(17000, entry1->ReadData(1, 0, buffer1, sizeof(buffer1), NULL)); + EXPECT_EQ(17000, entry1->WriteData(1, 20000, buffer1, sizeof(buffer1), NULL, + false)); + EXPECT_EQ(37000, entry1->GetDataSize(1)); + + entry1->Doom(); + entry1->Close(); + EXPECT_EQ(0, cache_->GetEntryCount()); +} + +TEST_F(DiskCacheEntryTest, ExternalSyncIO) { + InitCache(); + ExternalSyncIO(); +} + +TEST_F(DiskCacheEntryTest, MemoryOnlyExternalSyncIO) { + SetMemoryOnlyMode(); + InitCache(); + ExternalSyncIO(); +} + +void DiskCacheEntryTest::ExternalAsyncIO() { + disk_cache::Entry *entry1; + ASSERT_TRUE(cache_->CreateEntry("the first key", &entry1)); + + // Let's verify that each IO goes to the right callback object. + CallbackTest callback1(1, false); + CallbackTest callback2(2, false); + CallbackTest callback3(3, false); + CallbackTest callback4(4, false); + CallbackTest callback5(5, false); + CallbackTest callback6(6, false); + CallbackTest callback7(7, false); + CallbackTest callback8(8, false); + CallbackTest callback9(9, false); + + g_cache_tests_error = false; + g_cache_tests_max_id = 0; + g_cache_tests_received = 0; + int expected = 0; + + MessageLoopHelper helper; + + char buffer1[17000], buffer2[25000], buffer3[25000]; + CacheTestFillBuffer(buffer1, sizeof(buffer1), false); + CacheTestFillBuffer(buffer2, sizeof(buffer2), false); + CacheTestFillBuffer(buffer3, sizeof(buffer3), false); + strcpy_s(buffer1, "the data"); + int ret = entry1->WriteData(0, 0, buffer1, sizeof(buffer1), &callback1, + false); + EXPECT_TRUE(17000 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + g_cache_tests_max_id = 1; + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + + memset(buffer2, 0, sizeof(buffer1)); + ret = entry1->ReadData(0, 0, buffer2, sizeof(buffer1), &callback2); + EXPECT_TRUE(17000 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + g_cache_tests_max_id = 2; + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + EXPECT_STREQ("the data", buffer1); + + strcpy_s(buffer2, "The really big data goes here"); + ret = entry1->WriteData(1, 10000, buffer2, sizeof(buffer2), &callback3, + false); + EXPECT_TRUE(25000 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + g_cache_tests_max_id = 3; + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + + memset(buffer3, 0, sizeof(buffer3)); + ret = entry1->ReadData(1, 10011, buffer3, sizeof(buffer3), &callback4); + EXPECT_TRUE(24989 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + g_cache_tests_max_id = 4; + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + EXPECT_STREQ("big data goes here", buffer3); + ret = entry1->ReadData(1, 0, buffer2, sizeof(buffer2), &callback5); + EXPECT_TRUE(25000 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + g_cache_tests_max_id = 5; + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + EXPECT_EQ(0, memcmp(buffer2, buffer2, 10000)); + ret = entry1->ReadData(1, 30000, buffer2, sizeof(buffer2), &callback6); + EXPECT_TRUE(5000 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + + EXPECT_EQ(0, entry1->ReadData(1, 35000, buffer2, sizeof(buffer2), + &callback7)); + ret = entry1->ReadData(1, 0, buffer1, sizeof(buffer1), &callback8); + EXPECT_TRUE(17000 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + ret = entry1->WriteData(1, 20000, buffer1, sizeof(buffer1), &callback9, + false); + EXPECT_TRUE(17000 == ret || net::ERR_IO_PENDING == ret); + if (net::ERR_IO_PENDING == ret) + expected++; + EXPECT_EQ(37000, entry1->GetDataSize(1)); + + g_cache_tests_max_id = 9; + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + + EXPECT_FALSE(g_cache_tests_error); + EXPECT_EQ(expected, g_cache_tests_received); + + entry1->Doom(); + entry1->Close(); + EXPECT_EQ(0, cache_->GetEntryCount()); +} + +TEST_F(DiskCacheEntryTest, ExternalAsyncIO) { + InitCache(); + ExternalAsyncIO(); +} + +TEST_F(DiskCacheEntryTest, MemoryOnlyExternalAsyncIO) { + SetMemoryOnlyMode(); + InitCache(); + ExternalAsyncIO(); +} + +void DiskCacheEntryTest::GetKey() { + std::string key1("the first key"); + disk_cache::Entry *entry1; + ASSERT_TRUE(cache_->CreateEntry(key1, &entry1)); + EXPECT_EQ(key1, entry1->GetKey()) << "short key"; + entry1->Close(); + + int seed = static_cast<int>(Time::Now().ToInternalValue()); + srand(seed); + char key_buffer[20000]; + + CacheTestFillBuffer(key_buffer, 3000, true); + key_buffer[1000] = '\0'; + + key1 = key_buffer; + ASSERT_TRUE(cache_->CreateEntry(key1, &entry1)); + EXPECT_TRUE(key1 == entry1->GetKey()) << "1000 bytes key"; + entry1->Close(); + + key_buffer[1000] = 'p'; + key_buffer[3000] = '\0'; + key1 = key_buffer; + ASSERT_TRUE(cache_->CreateEntry(key1, &entry1)); + EXPECT_TRUE(key1 == entry1->GetKey()) << "medium size key"; + entry1->Close(); + + CacheTestFillBuffer(key_buffer, sizeof(key_buffer), true); + key_buffer[19999] = '\0'; + + key1 = key_buffer; + ASSERT_TRUE(cache_->CreateEntry(key1, &entry1)); + EXPECT_TRUE(key1 == entry1->GetKey()) << "long key"; + entry1->Close(); +} + +TEST_F(DiskCacheEntryTest, GetKey) { + InitCache(); + GetKey(); +} + +TEST_F(DiskCacheEntryTest, MemoryOnlyGetKey) { + SetMemoryOnlyMode(); + InitCache(); + GetKey(); +} + +void DiskCacheEntryTest::GrowData() { + std::string key1("the first key"); + disk_cache::Entry *entry1, *entry2; + ASSERT_TRUE(cache_->CreateEntry(key1, &entry1)); + + char buffer1[20000]; + char buffer2[20000]; + CacheTestFillBuffer(buffer1, sizeof(buffer1), false); + memset(buffer2, 0, sizeof(buffer2)); + + strcpy_s(buffer1, "the data"); + EXPECT_EQ(10, entry1->WriteData(0, 0, buffer1, 10, NULL, false)); + EXPECT_EQ(10, entry1->ReadData(0, 0, buffer2, 10, NULL)); + EXPECT_STREQ("the data", buffer2); + EXPECT_EQ(10, entry1->GetDataSize(0)); + + EXPECT_EQ(2000, entry1->WriteData(0, 0, buffer1, 2000, NULL, false)); + EXPECT_EQ(2000, entry1->GetDataSize(0)); + EXPECT_EQ(2000, entry1->ReadData(0, 0, buffer2, 2000, NULL)); + EXPECT_TRUE(!memcmp(buffer1, buffer2, 2000)); + + EXPECT_EQ(20000, entry1->WriteData(0, 0, buffer1, sizeof(buffer1), NULL, + false)); + EXPECT_EQ(20000, entry1->GetDataSize(0)); + EXPECT_EQ(20000, entry1->ReadData(0, 0, buffer2, sizeof(buffer2), NULL)); + EXPECT_TRUE(!memcmp(buffer1, buffer2, sizeof(buffer1))); + entry1->Close(); + + memset(buffer2, 0, sizeof(buffer2)); + ASSERT_TRUE(cache_->CreateEntry("Second key", &entry2)); + EXPECT_EQ(10, entry2->WriteData(0, 0, buffer1, 10, NULL, false)); + EXPECT_EQ(10, entry2->GetDataSize(0)); + entry2->Close(); + + // Go from an internal address to a bigger block size. + ASSERT_TRUE(cache_->OpenEntry("Second key", &entry2)); + EXPECT_EQ(2000, entry2->WriteData(0, 0, buffer1, 2000, NULL, false)); + EXPECT_EQ(2000, entry2->GetDataSize(0)); + EXPECT_EQ(2000, entry2->ReadData(0, 0, buffer2, 2000, NULL)); + EXPECT_TRUE(!memcmp(buffer1, buffer2, 2000)); + entry2->Close(); + memset(buffer2, 0, sizeof(buffer2)); + + // Go from an internal address to an external one. + ASSERT_TRUE(cache_->OpenEntry("Second key", &entry2)); + EXPECT_EQ(20000, entry2->WriteData(0, 0, buffer1, sizeof(buffer1), NULL, + false)); + EXPECT_EQ(20000, entry2->GetDataSize(0)); + EXPECT_EQ(20000, entry2->ReadData(0, 0, buffer2, sizeof(buffer2), NULL)); + EXPECT_TRUE(!memcmp(buffer1, buffer2, sizeof(buffer1))); + entry2->Close(); +} + +TEST_F(DiskCacheEntryTest, GrowData) { + InitCache(); + GrowData(); +} + +TEST_F(DiskCacheEntryTest, MemoryOnlyGrowData) { + SetMemoryOnlyMode(); + InitCache(); + GrowData(); +} + +void DiskCacheEntryTest::TruncateData() { + std::string key1("the first key"); + disk_cache::Entry *entry1; + ASSERT_TRUE(cache_->CreateEntry(key1, &entry1)); + + char buffer1[20000]; + char buffer2[20000]; + + CacheTestFillBuffer(buffer1, sizeof(buffer1), false); + memset(buffer2, 0, sizeof(buffer2)); + + // Simple truncation: + EXPECT_EQ(200, entry1->WriteData(0, 0, buffer1, 200, NULL, false)); + EXPECT_EQ(200, entry1->GetDataSize(0)); + EXPECT_EQ(100, entry1->WriteData(0, 0, buffer1, 100, NULL, false)); + EXPECT_EQ(200, entry1->GetDataSize(0)); + EXPECT_EQ(100, entry1->WriteData(0, 0, buffer1, 100, NULL, true)); + EXPECT_EQ(100, entry1->GetDataSize(0)); + EXPECT_EQ(0, entry1->WriteData(0, 50, buffer1, 0, NULL, true)); + EXPECT_EQ(50, entry1->GetDataSize(0)); + EXPECT_EQ(0, entry1->WriteData(0, 0, buffer1, 0, NULL, true)); + EXPECT_EQ(0, entry1->GetDataSize(0)); + entry1->Close(); + ASSERT_TRUE(cache_->OpenEntry(key1, &entry1)); + + // Go to an external file. + EXPECT_EQ(20000, entry1->WriteData(0, 0, buffer1, 20000, NULL, true)); + EXPECT_EQ(20000, entry1->GetDataSize(0)); + EXPECT_EQ(20000, entry1->ReadData(0, 0, buffer2, 20000, NULL)); + EXPECT_TRUE(!memcmp(buffer1, buffer2, 20000)); + memset(buffer2, 0, sizeof(buffer2)); + + // External file truncation + EXPECT_EQ(18000, entry1->WriteData(0, 0, buffer1, 18000, NULL, false)); + EXPECT_EQ(20000, entry1->GetDataSize(0)); + EXPECT_EQ(18000, entry1->WriteData(0, 0, buffer1, 18000, NULL, true)); + EXPECT_EQ(18000, entry1->GetDataSize(0)); + EXPECT_EQ(0, entry1->WriteData(0, 17500, buffer1, 0, NULL, true)); + EXPECT_EQ(17500, entry1->GetDataSize(0)); + + // And back to an internal block. + EXPECT_EQ(600, entry1->WriteData(0, 1000, buffer1, 600, NULL, true)); + EXPECT_EQ(1600, entry1->GetDataSize(0)); + EXPECT_EQ(600, entry1->ReadData(0, 1000, buffer2, 600, NULL)); + EXPECT_TRUE(!memcmp(buffer1, buffer2, 600)); + EXPECT_EQ(1000, entry1->ReadData(0, 0, buffer2, 1000, NULL)); + EXPECT_TRUE(!memcmp(buffer1, buffer2, 1000)) << "Preserves previous data"; + + // Go from external file to zero length. + EXPECT_EQ(20000, entry1->WriteData(0, 0, buffer1, 20000, NULL, true)); + EXPECT_EQ(20000, entry1->GetDataSize(0)); + EXPECT_EQ(0, entry1->WriteData(0, 0, buffer1, 0, NULL, true)); + EXPECT_EQ(0, entry1->GetDataSize(0)); + + entry1->Close(); +} + +TEST_F(DiskCacheEntryTest, TruncateData) { + InitCache(); + TruncateData(); +} + +TEST_F(DiskCacheEntryTest, MemoryOnlyTruncateData) { + SetMemoryOnlyMode(); + InitCache(); + TruncateData(); +} + +// Reading somewhere that was not written should return zeros. +void DiskCacheEntryTest::InvalidData() { + std::string key1("the first key"); + disk_cache::Entry *entry1; + ASSERT_TRUE(cache_->CreateEntry(key1, &entry1)); + + char buffer1[20000]; + char buffer2[20000]; + char buffer3[20000]; + + CacheTestFillBuffer(buffer1, sizeof(buffer1), false); + memset(buffer2, 0, sizeof(buffer2)); + + // Simple data grow: + EXPECT_EQ(200, entry1->WriteData(0, 400, buffer1, 200, NULL, false)); + EXPECT_EQ(600, entry1->GetDataSize(0)); + EXPECT_EQ(100, entry1->ReadData(0, 300, buffer3, 100, NULL)); + EXPECT_TRUE(!memcmp(buffer3, buffer2, 100)); + entry1->Close(); + ASSERT_TRUE(cache_->OpenEntry(key1, &entry1)); + + // The entry is now on disk. Load it and extend it. + EXPECT_EQ(200, entry1->WriteData(0, 800, buffer1, 200, NULL, false)); + EXPECT_EQ(1000, entry1->GetDataSize(0)); + EXPECT_EQ(100, entry1->ReadData(0, 700, buffer3, 100, NULL)); + EXPECT_TRUE(!memcmp(buffer3, buffer2, 100)); + entry1->Close(); + ASSERT_TRUE(cache_->OpenEntry(key1, &entry1)); + + // This time using truncate. + EXPECT_EQ(200, entry1->WriteData(0, 1800, buffer1, 200, NULL, true)); + EXPECT_EQ(2000, entry1->GetDataSize(0)); + EXPECT_EQ(100, entry1->ReadData(0, 1500, buffer3, 100, NULL)); + EXPECT_TRUE(!memcmp(buffer3, buffer2, 100)); + + // Go to an external file. + EXPECT_EQ(200, entry1->WriteData(0, 19800, buffer1, 200, NULL, false)); + EXPECT_EQ(20000, entry1->GetDataSize(0)); + EXPECT_EQ(4000, entry1->ReadData(0, 14000, buffer3, 4000, NULL)); + EXPECT_TRUE(!memcmp(buffer3, buffer2, 4000)); + + // And back to an internal block. + EXPECT_EQ(600, entry1->WriteData(0, 1000, buffer1, 600, NULL, true)); + EXPECT_EQ(1600, entry1->GetDataSize(0)); + EXPECT_EQ(600, entry1->ReadData(0, 1000, buffer3, 600, NULL)); + EXPECT_TRUE(!memcmp(buffer3, buffer1, 600)); + + // Extend it again. + EXPECT_EQ(600, entry1->WriteData(0, 2000, buffer1, 600, NULL, false)); + EXPECT_EQ(2600, entry1->GetDataSize(0)); + EXPECT_EQ(200, entry1->ReadData(0, 1800, buffer3, 200, NULL)); + EXPECT_TRUE(!memcmp(buffer3, buffer2, 200)); + + // And again (with truncation flag). + EXPECT_EQ(600, entry1->WriteData(0, 3000, buffer1, 600, NULL, true)); + EXPECT_EQ(3600, entry1->GetDataSize(0)); + EXPECT_EQ(200, entry1->ReadData(0, 2800, buffer3, 200, NULL)); + EXPECT_TRUE(!memcmp(buffer3, buffer2, 200)); + + entry1->Close(); +} + +TEST_F(DiskCacheEntryTest, InvalidData) { + InitCache(); + InvalidData(); +} + +TEST_F(DiskCacheEntryTest, MemoryOnlyInvalidData) { + SetMemoryOnlyMode(); + InitCache(); + InvalidData(); +} + +void DiskCacheEntryTest::DoomEntry() { + std::string key1("the first key"); + disk_cache::Entry *entry1; + ASSERT_TRUE(cache_->CreateEntry(key1, &entry1)); + entry1->Doom(); + entry1->Close(); + + char key_buffer[20000]; + CacheTestFillBuffer(key_buffer, sizeof(key_buffer), true); + key_buffer[19999] = '\0'; + + key1 = key_buffer; + ASSERT_TRUE(cache_->CreateEntry(key1, &entry1)); + EXPECT_EQ(20000, entry1->WriteData(0, 0, key_buffer, 20000, NULL, false)); + EXPECT_EQ(20000, entry1->WriteData(1, 0, key_buffer, 20000, NULL, false)); + entry1->Doom(); + entry1->Close(); + + EXPECT_EQ(0, cache_->GetEntryCount()); +} + +TEST_F(DiskCacheEntryTest, DoomEntry) { + InitCache(); + DoomEntry(); +} + +TEST_F(DiskCacheEntryTest, MemoryOnlyDoomEntry) { + SetMemoryOnlyMode(); + InitCache(); + DoomEntry(); +} + +// Verify that basic operations work as expected with doomed entries. +void DiskCacheEntryTest::DoomedEntry() { + std::string key("the first key"); + disk_cache::Entry *entry; + ASSERT_TRUE(cache_->CreateEntry(key, &entry)); + entry->Doom(); + + EXPECT_EQ(0, cache_->GetEntryCount()); + Time initial = Time::Now(); + Sleep(20); + + char buffer1[2000]; + char buffer2[2000]; + CacheTestFillBuffer(buffer1, sizeof(buffer1), false); + memset(buffer2, 0, sizeof(buffer2)); + + EXPECT_EQ(2000, entry->WriteData(0, 0, buffer1, 2000, NULL, false)); + EXPECT_EQ(2000, entry->ReadData(0, 0, buffer2, 2000, NULL)); + EXPECT_EQ(0, memcmp(buffer1, buffer2, sizeof(buffer1))); + EXPECT_TRUE(initial < entry->GetLastModified()); + EXPECT_TRUE(initial < entry->GetLastUsed()); + + entry->Close(); +} + +TEST_F(DiskCacheEntryTest, DoomedEntry) { + InitCache(); + DoomEntry(); +} + +TEST_F(DiskCacheEntryTest, MemoryOnlyDoomedEntry) { + SetMemoryOnlyMode(); + InitCache(); + DoomEntry(); +} |