Chromium Code Reviews| Index: base/win/memory_pressure_monitor_unittest.cc |
| diff --git a/base/win/memory_pressure_monitor_unittest.cc b/base/win/memory_pressure_monitor_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..1bc64108f7c7098790b96e78f6625b519b72adbb |
| --- /dev/null |
| +++ b/base/win/memory_pressure_monitor_unittest.cc |
| @@ -0,0 +1,303 @@ |
| +// Copyright 2015 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/win/memory_pressure_monitor.h" |
| + |
| +#include "base/basictypes.h" |
| +#include "base/memory/memory_pressure_listener.h" |
| +#include "base/message_loop/message_loop.h" |
| +#include "testing/gmock/include/gmock/gmock.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace base { |
| +namespace win { |
| + |
| +namespace { |
| + |
| +struct PressureSettings { |
| + int phys_left_mb; |
| + MemoryPressureListener::MemoryPressureLevel level; |
| +}; |
| + |
| +} // namespace |
| + |
| +// This is outside of the anonymous namespace so that it can be seen as a friend |
| +// to the monitor class. |
| +class TestMemoryPressureMonitor : public MemoryPressureMonitor { |
| + public: |
| + using MemoryPressureMonitor::CalculateCurrentPressureLevel; |
| + using MemoryPressureMonitor::CheckMemoryPressure; |
| + |
| + static const DWORDLONG kMBBytes = 1024 * 1024; |
| + |
| + TestMemoryPressureMonitor(bool high_memory) { |
|
grt (UTC plus 2)
2015/05/07 02:12:11
explicit
grt (UTC plus 2)
2015/05/07 02:12:12
: mem_status_() to default-initialize it (which wi
|
| + // Generate a plausible amount of memory. |
| + mem_status_.ullTotalPhys = |
| + static_cast<DWORDLONG>(GenerateTotalMemoryMb(high_memory)) * kMBBytes; |
| + |
| + // Rerun InferThresholds using the test fixture's GetSystemMemoryStatus. |
| + InferThresholds(); |
| + // Stop the timer. |
| + StopObserving(); |
| + } |
| + |
| + TestMemoryPressureMonitor(int system_memory_mb, |
| + int moderate_threshold_mb, |
| + int critical_threshold_mb) |
| + : MemoryPressureMonitor(moderate_threshold_mb, critical_threshold_mb) { |
|
grt (UTC plus 2)
2015/05/07 02:12:12
, mem_status_() here, too
chrisha
2015/05/07 21:17:36
Done.
|
| + // Set the amount of system memory. |
| + mem_status_.ullTotalPhys = static_cast<DWORDLONG>( |
| + system_memory_mb * kMBBytes); |
| + |
| + // Stop the timer. |
| + StopObserving(); |
| + } |
| + |
| + virtual ~TestMemoryPressureMonitor() {} |
| + |
| + MOCK_METHOD1(OnMemoryPressure, |
| + void(MemoryPressureListener::MemoryPressureLevel level)); |
| + |
| + // Generates an amount of total memory that is consistent with the requested |
| + // memory model. |
| + int GenerateTotalMemoryMb(bool high_memory) { |
| + int total_mb = 64; |
| + while (total_mb < MemoryPressureMonitor::kHighMemoryThresholdMb) |
| + total_mb *= 2; |
| + if (high_memory) |
| + return total_mb * 2; |
| + return total_mb / 2; |
| + } |
| + |
| + // Sets up the memory status to reflect the provided absolute memory left. |
| + void SetMemoryFree(int phys_left_mb) { |
| + // ullTotalPhys is set in the constructor and not modified. |
| + |
| + // Set the amount of available memory. |
| + mem_status_.ullAvailPhys = |
| + static_cast<DWORDLONG>(phys_left_mb) * kMBBytes; |
| + DCHECK_LT(mem_status_.ullAvailPhys, mem_status_.ullTotalPhys); |
| + |
| + // These fields are unused. |
| + mem_status_.dwMemoryLoad = 0; |
| + mem_status_.ullTotalPageFile = 0; |
| + mem_status_.ullAvailPageFile = 0; |
| + mem_status_.ullTotalVirtual = 0; |
| + mem_status_.ullAvailVirtual = 0; |
| + } |
| + |
| + void SetNone() { |
| + SetMemoryFree(moderate_threshold_mb() + 1); |
| + } |
| + |
| + void SetModerate() { |
| + SetMemoryFree(moderate_threshold_mb() - 1); |
| + } |
| + |
| + void SetCritical() { |
| + SetMemoryFree(critical_threshold_mb() - 1); |
| + } |
| + |
| + private: |
| + bool GetSystemMemoryStatus(MEMORYSTATUSEX* mem_status) override { |
| + // Simply copy the memory status set by the test fixture. |
| + *mem_status = mem_status_; |
| + return true; |
| + } |
| + |
| + MEMORYSTATUSEX mem_status_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor); |
| +}; |
| + |
| +namespace { |
|
grt (UTC plus 2)
2015/05/07 02:12:12
remove this: don't put the test fixture in the unn
|
| + |
| +class WinMemoryPressureMonitorTest : public testing::Test { |
| + public: |
|
grt (UTC plus 2)
2015/05/07 02:12:11
protected:
(each individual TEST_F ends up being a
|
| + ~WinMemoryPressureMonitorTest() override { } |
|
grt (UTC plus 2)
2015/05/07 02:12:12
remove; not needed
chrisha
2015/05/07 21:17:36
Done.
|
| + |
| + void CalculateCurrentMemoryPressureLevelTest( |
| + TestMemoryPressureMonitor* monitor) { |
| + int mod = monitor->moderate_threshold_mb(); |
| + int crit = monitor->critical_threshold_mb(); |
|
grt (UTC plus 2)
2015/05/07 02:12:11
nit: move down to line 136 so its definition is "a
chrisha
2015/05/07 21:17:36
Done.
|
| + |
| + monitor->SetMemoryFree(mod + 1); |
| + EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, |
| + monitor->CalculateCurrentPressureLevel()); |
| + |
| + monitor->SetMemoryFree(mod); |
| + EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, |
| + monitor->CalculateCurrentPressureLevel()); |
| + |
| + monitor->SetMemoryFree(mod - 1); |
| + EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, |
| + monitor->CalculateCurrentPressureLevel()); |
| + |
| + monitor->SetMemoryFree(crit + 1); |
| + EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, |
| + monitor->CalculateCurrentPressureLevel()); |
| + |
| + monitor->SetMemoryFree(crit); |
| + EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, |
| + monitor->CalculateCurrentPressureLevel()); |
| + |
| + monitor->SetMemoryFree(crit - 1); |
| + EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, |
| + monitor->CalculateCurrentPressureLevel()); |
| + } |
| +}; |
| + |
| +} // namespace |
| + |
| +// Tests the fundamental direct calculation of memory pressure with automatic |
| +// low-memory thresholds. |
| +TEST_F(WinMemoryPressureMonitorTest, CalculateCurrentMemoryPressureLevelLow) { |
| + static const int kModerateMb = |
| + MemoryPressureMonitor::kLowMemoryDefaultModerateThresholdMb; |
| + static const int kCriticalMb = |
| + MemoryPressureMonitor::kLowMemoryDefaultCriticalThresholdMb; |
| + |
| + base::MessageLoopForUI message_loop; |
|
grt (UTC plus 2)
2015/05/07 02:12:11
now that you have a test fixture, make the Message
chrisha
2015/05/07 21:17:36
Done.
|
| + TestMemoryPressureMonitor monitor(false); // Low-memory model. |
| + |
| + EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb()); |
| + EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb()); |
| + |
| + ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor)); |
| +} |
| + |
| +// Tests the fundamental direct calculation of memory pressure with automatic |
| +// high-memory thresholds. |
| +TEST_F(WinMemoryPressureMonitorTest, CalculateCurrentMemoryPressureLevelHigh) { |
| + static const int kModerateMb = |
| + MemoryPressureMonitor::kHighMemoryDefaultModerateThresholdMb; |
| + static const int kCriticalMb = |
| + MemoryPressureMonitor::kHighMemoryDefaultCriticalThresholdMb; |
| + |
| + base::MessageLoopForUI message_loop; |
| + TestMemoryPressureMonitor monitor(true); // High-memory model. |
| + |
| + EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb()); |
| + EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb()); |
| + |
| + ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor)); |
| +} |
| + |
| +// Tests the fundamental direct calculation of memory pressure with manually |
| +// specified threshold levels. |
| +TEST_F(WinMemoryPressureMonitorTest, |
| + CalculateCurrentMemoryPressureLevelCustom) { |
| + static const int kSystemMb = 512; |
| + static const int kModerateMb = 256; |
| + static const int kCriticalMb = 128; |
| + |
| + base::MessageLoopForUI message_loop; |
| + TestMemoryPressureMonitor monitor(kSystemMb, kModerateMb, kCriticalMb); |
| + |
| + EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb()); |
| + EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb()); |
| + |
| + ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor)); |
| +} |
| + |
| +// This test tests the various transition states from memory pressure, looking |
| +// for the correct behavior on event reposting as well as state updates. |
| +TEST_F(WinMemoryPressureMonitorTest, CheckMemoryPressure) { |
| + base::MessageLoopForUI message_loop; |
| + testing::StrictMock<TestMemoryPressureMonitor> monitor(true); // High-memory. |
| + MemoryPressureListener listener( |
| + base::Bind(&TestMemoryPressureMonitor::OnMemoryPressure, |
| + base::Unretained(&monitor))); |
| + |
| + // Checking the memory pressure at 0% load should not produce any |
| + // events. |
| + monitor.SetNone(); |
| + monitor.CheckMemoryPressure(); |
| + message_loop.RunUntilIdle(); |
| + EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, |
| + monitor.GetCurrentPressureLevel()); |
| + |
| + // Setting the memory level to 80% should produce a moderate pressure level. |
| + EXPECT_CALL(monitor, |
| + OnMemoryPressure(MemoryPressureListener:: |
| + MEMORY_PRESSURE_LEVEL_MODERATE)); |
| + monitor.SetModerate(); |
| + monitor.CheckMemoryPressure(); |
| + message_loop.RunUntilIdle(); |
| + EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, |
| + monitor.GetCurrentPressureLevel()); |
| + testing::Mock::VerifyAndClearExpectations(&monitor); |
| + |
| + // Check that the event gets reposted after a while. |
| + for (int i = 0; i < monitor.kModeratePressureCooldownCycles; ++i) { |
| + if (i + 1 == monitor.kModeratePressureCooldownCycles) { |
| + EXPECT_CALL(monitor, |
| + OnMemoryPressure(MemoryPressureListener:: |
| + MEMORY_PRESSURE_LEVEL_MODERATE)); |
| + } |
| + monitor.CheckMemoryPressure(); |
| + message_loop.RunUntilIdle(); |
| + EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, |
| + monitor.GetCurrentPressureLevel()); |
| + testing::Mock::VerifyAndClearExpectations(&monitor); |
| + } |
| + |
| + // Setting the memory usage to 99% should produce critical levels. |
| + EXPECT_CALL(monitor, |
| + OnMemoryPressure(MemoryPressureListener:: |
| + MEMORY_PRESSURE_LEVEL_CRITICAL)); |
| + monitor.SetCritical(); |
| + monitor.CheckMemoryPressure(); |
| + message_loop.RunUntilIdle(); |
| + EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, |
| + monitor.GetCurrentPressureLevel()); |
| + testing::Mock::VerifyAndClearExpectations(&monitor); |
| + |
| + // Calling it again should immediately produce a second call. |
| + EXPECT_CALL(monitor, |
| + OnMemoryPressure(MemoryPressureListener:: |
| + MEMORY_PRESSURE_LEVEL_CRITICAL)); |
| + monitor.CheckMemoryPressure(); |
| + message_loop.RunUntilIdle(); |
| + EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, |
| + monitor.GetCurrentPressureLevel()); |
| + testing::Mock::VerifyAndClearExpectations(&monitor); |
| + |
| + // When lowering the pressure again there should be a notification and the |
| + // pressure should go back to moderate. |
| + EXPECT_CALL(monitor, |
| + OnMemoryPressure(MemoryPressureListener:: |
| + MEMORY_PRESSURE_LEVEL_MODERATE)); |
| + monitor.SetModerate(); |
| + monitor.CheckMemoryPressure(); |
| + message_loop.RunUntilIdle(); |
| + EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, |
| + monitor.GetCurrentPressureLevel()); |
| + testing::Mock::VerifyAndClearExpectations(&monitor); |
| + |
| + // Check that the event gets reposted after a while. |
| + for (int i = 0; i < monitor.kModeratePressureCooldownCycles; ++i) { |
| + if (i + 1 == monitor.kModeratePressureCooldownCycles) { |
| + EXPECT_CALL(monitor, |
| + OnMemoryPressure(MemoryPressureListener:: |
| + MEMORY_PRESSURE_LEVEL_MODERATE)); |
| + } |
| + monitor.CheckMemoryPressure(); |
| + message_loop.RunUntilIdle(); |
| + EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, |
| + monitor.GetCurrentPressureLevel()); |
| + testing::Mock::VerifyAndClearExpectations(&monitor); |
| + } |
| + |
| + // Going down to no pressure should not produce an notification. |
| + monitor.SetNone(); |
| + monitor.CheckMemoryPressure(); |
| + message_loop.RunUntilIdle(); |
| + EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, |
| + monitor.GetCurrentPressureLevel()); |
| + testing::Mock::VerifyAndClearExpectations(&monitor); |
| +} |
| + |
| +} // namespace win |
| +} // namespace base |