| Index: base/memory/discardable_shared_memory_unittest.cc
|
| diff --git a/base/memory/discardable_shared_memory_unittest.cc b/base/memory/discardable_shared_memory_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e5174298bfd8a7f74920b00dbdb650fde9aef086
|
| --- /dev/null
|
| +++ b/base/memory/discardable_shared_memory_unittest.cc
|
| @@ -0,0 +1,251 @@
|
| +// Copyright 2014 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/memory/discardable_shared_memory.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace base {
|
| +namespace {
|
| +
|
| +class TestDiscardableSharedMemory : public DiscardableSharedMemory {
|
| + public:
|
| + TestDiscardableSharedMemory() {}
|
| +
|
| + explicit TestDiscardableSharedMemory(SharedMemoryHandle handle)
|
| + : DiscardableSharedMemory(handle) {}
|
| +
|
| + void SetNow(Time now) { now_ = now; }
|
| +
|
| + private:
|
| + // Overriden from DiscardableSharedMemory:
|
| + virtual Time Now() const override { return now_; }
|
| +
|
| + Time now_;
|
| +};
|
| +
|
| +TEST(DiscardableSharedMemoryTest, CreateAndMap) {
|
| + const uint32 kDataSize = 1024;
|
| +
|
| + TestDiscardableSharedMemory memory;
|
| + bool rv = memory.CreateAndMap(kDataSize);
|
| + ASSERT_TRUE(rv);
|
| + EXPECT_GE(memory.mapped_size(), kDataSize);
|
| +}
|
| +
|
| +TEST(DiscardableSharedMemoryTest, CreateFromHandle) {
|
| + const uint32 kDataSize = 1024;
|
| +
|
| + TestDiscardableSharedMemory memory1;
|
| + bool rv = memory1.CreateAndMap(kDataSize);
|
| + ASSERT_TRUE(rv);
|
| +
|
| + SharedMemoryHandle shared_handle;
|
| + ASSERT_TRUE(
|
| + memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
|
| + ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
|
| +
|
| + TestDiscardableSharedMemory memory2(shared_handle);
|
| + rv = memory2.Map(kDataSize);
|
| + ASSERT_TRUE(rv);
|
| +}
|
| +
|
| +TEST(DiscardableSharedMemoryTest, LockAndUnlock) {
|
| + const uint32 kDataSize = 1024;
|
| +
|
| + TestDiscardableSharedMemory memory1;
|
| + bool rv = memory1.CreateAndMap(kDataSize);
|
| + ASSERT_TRUE(rv);
|
| +
|
| + // Memory is initially locked. Unlock it.
|
| + memory1.SetNow(Time::FromDoubleT(1));
|
| + memory1.Unlock();
|
| +
|
| + // Lock and unlock memory.
|
| + rv = memory1.Lock();
|
| + EXPECT_TRUE(rv);
|
| + memory1.SetNow(Time::FromDoubleT(2));
|
| + memory1.Unlock();
|
| +
|
| + SharedMemoryHandle shared_handle;
|
| + ASSERT_TRUE(
|
| + memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
|
| + ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
|
| +
|
| + TestDiscardableSharedMemory memory2(shared_handle);
|
| + rv = memory2.Map(kDataSize);
|
| + ASSERT_TRUE(rv);
|
| +
|
| + // Lock first instance again.
|
| + rv = memory1.Lock();
|
| + EXPECT_TRUE(rv);
|
| +
|
| + // Unlock second instance.
|
| + memory2.SetNow(Time::FromDoubleT(3));
|
| + memory2.Unlock();
|
| +
|
| + // Lock and unlock second instance.
|
| + rv = memory2.Lock();
|
| + EXPECT_TRUE(rv);
|
| + memory2.SetNow(Time::FromDoubleT(4));
|
| + memory2.Unlock();
|
| +
|
| + // Try to lock first instance again. Should fail as first instance has an
|
| + // incorrect last know usage time.
|
| + rv = memory1.Lock();
|
| + EXPECT_FALSE(rv);
|
| +
|
| + // Memory should still be resident.
|
| + rv = memory1.IsMemoryResident();
|
| + EXPECT_TRUE(rv);
|
| +
|
| + // Second attempt to lock first instance should succeed as last known usage
|
| + // time is now correct.
|
| + rv = memory1.Lock();
|
| + EXPECT_TRUE(rv);
|
| + memory1.SetNow(Time::FromDoubleT(5));
|
| + memory1.Unlock();
|
| +}
|
| +
|
| +TEST(DiscardableSharedMemoryTest, Purge) {
|
| + const uint32 kDataSize = 1024;
|
| +
|
| + TestDiscardableSharedMemory memory1;
|
| + bool rv = memory1.CreateAndMap(kDataSize);
|
| + ASSERT_TRUE(rv);
|
| +
|
| + SharedMemoryHandle shared_handle;
|
| + ASSERT_TRUE(
|
| + memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
|
| + ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
|
| +
|
| + TestDiscardableSharedMemory memory2(shared_handle);
|
| + rv = memory2.Map(kDataSize);
|
| + ASSERT_TRUE(rv);
|
| +
|
| + // This should fail as memory is locked.
|
| + rv = memory1.Purge(Time::FromDoubleT(1));
|
| + EXPECT_FALSE(rv);
|
| +
|
| + memory2.SetNow(Time::FromDoubleT(2));
|
| + memory2.Unlock();
|
| +
|
| + ASSERT_TRUE(memory2.IsMemoryResident());
|
| +
|
| + // Memory is unlocked, but our usage timestamp is incorrect.
|
| + rv = memory1.Purge(Time::FromDoubleT(3));
|
| + EXPECT_FALSE(rv);
|
| +
|
| + ASSERT_TRUE(memory2.IsMemoryResident());
|
| +
|
| + // Memory is unlocked and our usage timestamp should be correct.
|
| + rv = memory1.Purge(Time::FromDoubleT(4));
|
| + EXPECT_TRUE(rv);
|
| +
|
| + // Lock should fail as memory has been purged.
|
| + rv = memory2.Lock();
|
| + EXPECT_FALSE(rv);
|
| +
|
| + ASSERT_FALSE(memory2.IsMemoryResident());
|
| +}
|
| +
|
| +TEST(DiscardableSharedMemoryTest, LastUsed) {
|
| + const uint32 kDataSize = 1024;
|
| +
|
| + TestDiscardableSharedMemory memory1;
|
| + bool rv = memory1.CreateAndMap(kDataSize);
|
| + ASSERT_TRUE(rv);
|
| +
|
| + SharedMemoryHandle shared_handle;
|
| + ASSERT_TRUE(
|
| + memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
|
| + ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
|
| +
|
| + TestDiscardableSharedMemory memory2(shared_handle);
|
| + rv = memory2.Map(kDataSize);
|
| + ASSERT_TRUE(rv);
|
| +
|
| + memory2.SetNow(Time::FromDoubleT(1));
|
| + memory2.Unlock();
|
| +
|
| + EXPECT_EQ(memory2.last_known_usage(), Time::FromDoubleT(1));
|
| +
|
| + rv = memory2.Lock();
|
| + EXPECT_TRUE(rv);
|
| +
|
| + // This should fail as memory is locked.
|
| + rv = memory1.Purge(Time::FromDoubleT(2));
|
| + ASSERT_FALSE(rv);
|
| +
|
| + // Last usage should have been updated to timestamp passed to Purge above.
|
| + EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(2));
|
| +
|
| + memory2.SetNow(Time::FromDoubleT(3));
|
| + memory2.Unlock();
|
| +
|
| + // Usage time should be correct for |memory2| instance.
|
| + EXPECT_EQ(memory2.last_known_usage(), Time::FromDoubleT(3));
|
| +
|
| + // However, usage time has not changed as far as |memory1| instance knows.
|
| + EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(2));
|
| +
|
| + // Memory is unlocked, but our usage timestamp is incorrect.
|
| + rv = memory1.Purge(Time::FromDoubleT(4));
|
| + EXPECT_FALSE(rv);
|
| +
|
| + // The failed purge attempt should have updated usage time to the correct
|
| + // value.
|
| + EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(3));
|
| +
|
| + // Purge memory through |memory2| instance. The last usage time should be
|
| + // set to 0 as a result of this.
|
| + rv = memory2.Purge(Time::FromDoubleT(5));
|
| + EXPECT_TRUE(rv);
|
| + EXPECT_TRUE(memory2.last_known_usage().is_null());
|
| +
|
| + // This should fail as memory has already been purged and |memory1|'s usage
|
| + // time is incorrect as a result.
|
| + rv = memory1.Purge(Time::FromDoubleT(6));
|
| + EXPECT_FALSE(rv);
|
| +
|
| + // The failed purge attempt should have updated usage time to the correct
|
| + // value.
|
| + EXPECT_TRUE(memory1.last_known_usage().is_null());
|
| +
|
| + // Purge should succeed now that usage time is correct.
|
| + rv = memory1.Purge(Time::FromDoubleT(7));
|
| + EXPECT_TRUE(rv);
|
| +}
|
| +
|
| +TEST(DiscardableSharedMemoryTest, LockShouldAlwaysFailAfterSuccessfulPurge) {
|
| + const uint32 kDataSize = 1024;
|
| +
|
| + TestDiscardableSharedMemory memory1;
|
| + bool rv = memory1.CreateAndMap(kDataSize);
|
| + ASSERT_TRUE(rv);
|
| +
|
| + SharedMemoryHandle shared_handle;
|
| + ASSERT_TRUE(
|
| + memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
|
| + ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
|
| +
|
| + TestDiscardableSharedMemory memory2(shared_handle);
|
| + rv = memory2.Map(kDataSize);
|
| + ASSERT_TRUE(rv);
|
| +
|
| + memory2.SetNow(Time::FromDoubleT(1));
|
| + memory2.Unlock();
|
| +
|
| + rv = memory2.Purge(Time::FromDoubleT(2));
|
| + EXPECT_TRUE(rv);
|
| +
|
| + // Lock should fail as memory has been purged.
|
| + rv = memory2.Lock();
|
| + EXPECT_FALSE(rv);
|
| + rv = memory1.Lock();
|
| + EXPECT_FALSE(rv);
|
| +}
|
| +
|
| +} // namespace
|
| +} // namespace base
|
|
|