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..40a25a79dd8170ea9a86292d0ececeac04b410d6 |
--- /dev/null |
+++ b/base/win/memory_pressure_monitor_unittest.cc |
@@ -0,0 +1,298 @@ |
+// 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; |
+ |
+ explicit TestMemoryPressureMonitor(bool large_memory) |
+ : mem_status_() { |
+ // Generate a plausible amount of memory. |
+ mem_status_.ullTotalPhys = |
+ static_cast<DWORDLONG>(GenerateTotalMemoryMb(large_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), |
+ mem_status_() { |
+ // 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 large_memory) { |
+ int total_mb = 64; |
+ while (total_mb < MemoryPressureMonitor::kLargeMemoryThresholdMb) |
+ total_mb *= 2; |
+ if (large_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); |
+}; |
+ |
+class WinMemoryPressureMonitorTest : public testing::Test { |
+ protected: |
+ void CalculateCurrentMemoryPressureLevelTest( |
+ TestMemoryPressureMonitor* monitor) { |
+ |
+ int mod = monitor->moderate_threshold_mb(); |
+ 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()); |
+ |
+ int crit = monitor->critical_threshold_mb(); |
+ 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()); |
+ } |
+ |
+ base::MessageLoopForUI message_loop_; |
+}; |
+ |
+// Tests the fundamental direct calculation of memory pressure with automatic |
+// small-memory thresholds. |
+TEST_F(WinMemoryPressureMonitorTest, CalculateCurrentMemoryPressureLevelSmall) { |
+ static const int kModerateMb = |
+ MemoryPressureMonitor::kSmallMemoryDefaultModerateThresholdMb; |
+ static const int kCriticalMb = |
+ MemoryPressureMonitor::kSmallMemoryDefaultCriticalThresholdMb; |
+ |
+ TestMemoryPressureMonitor monitor(false); // Small-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 |
+// large-memory thresholds. |
+TEST_F(WinMemoryPressureMonitorTest, CalculateCurrentMemoryPressureLevelLarge) { |
+ static const int kModerateMb = |
+ MemoryPressureMonitor::kLargeMemoryDefaultModerateThresholdMb; |
+ static const int kCriticalMb = |
+ MemoryPressureMonitor::kLargeMemoryDefaultCriticalThresholdMb; |
+ |
+ TestMemoryPressureMonitor monitor(true); // Large-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; |
+ |
+ 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) { |
+ // Large-memory. |
+ testing::StrictMock<TestMemoryPressureMonitor> monitor(true); |
+ 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 |