blob: 95cea25227745ef2758b1a4cbf326f1670613507 [file] [log] [blame]
// Copyright 2017 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 "chrome/browser/android/oom_intervention/near_oom_monitor.h"
#include "base/message_loop/message_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/test/test_mock_time_task_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
const int64_t kTestSwapTotalKB = 128 * 1024;
const int64_t kTestSwapFreeThreshold = kTestSwapTotalKB / 4;
} // namespace
class MockNearOomMonitor : public NearOomMonitor {
public:
explicit MockNearOomMonitor(
scoped_refptr<base::SequencedTaskRunner> task_runner)
: NearOomMonitor(task_runner, kTestSwapFreeThreshold) {
// Start with 128MB swap total and 64MB swap free.
memory_info_.swap_total = kTestSwapTotalKB;
memory_info_.swap_free = kTestSwapTotalKB / 2;
}
void SetSwapFree(int swap_free) { memory_info_.swap_free = swap_free; }
void SimulateNonNearOom() {
memory_info_.swap_free = memory_info_.swap_total;
}
void SimulateNearOom() { memory_info_.swap_free = 0; }
bool is_get_system_memory_info_called() const {
return is_get_system_memory_info_called_;
}
private:
bool GetSystemMemoryInfo(base::SystemMemoryInfoKB* memory_info) override {
*memory_info = memory_info_;
is_get_system_memory_info_called_ = true;
return true;
}
bool ComponentCallbackIsEnabled() override { return false; }
base::SystemMemoryInfoKB memory_info_;
bool is_get_system_memory_info_called_ = false;
DISALLOW_COPY_AND_ASSIGN(MockNearOomMonitor);
};
class TestNearOomObserver {
public:
explicit TestNearOomObserver(NearOomMonitor* monitor) {
DCHECK(monitor);
subscription_ = monitor->RegisterCallback(base::Bind(
&TestNearOomObserver::OnNearOomDetected, base::Unretained(this)));
}
void Unsubscribe() { subscription_.reset(); }
bool is_detected() const { return is_detected_; }
private:
void OnNearOomDetected() { is_detected_ = true; }
bool is_detected_ = false;
std::unique_ptr<NearOomMonitor::Subscription> subscription_;
DISALLOW_COPY_AND_ASSIGN(TestNearOomObserver);
};
class NearOomMonitorTest : public testing::Test {
public:
void SetUp() override {
task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
monitor_ = std::make_unique<MockNearOomMonitor>(task_runner_);
}
protected:
scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
base::MessageLoop message_loop_;
std::unique_ptr<MockNearOomMonitor> monitor_;
};
TEST_F(NearOomMonitorTest, Observe) {
base::TimeDelta interval =
monitor_->GetMonitoringInterval() + base::TimeDelta::FromSeconds(1);
TestNearOomObserver observer1(monitor_.get());
TestNearOomObserver observer2(monitor_.get());
monitor_->SimulateNonNearOom();
task_runner_->FastForwardBy(interval);
EXPECT_TRUE(monitor_->is_get_system_memory_info_called());
EXPECT_FALSE(observer1.is_detected());
EXPECT_FALSE(observer2.is_detected());
observer2.Unsubscribe();
monitor_->SimulateNearOom();
task_runner_->FastForwardBy(interval);
EXPECT_TRUE(observer1.is_detected());
EXPECT_FALSE(observer2.is_detected());
observer1.Unsubscribe();
}
TEST_F(NearOomMonitorTest, Cooldown) {
base::TimeDelta interval =
monitor_->GetMonitoringInterval() + base::TimeDelta::FromSeconds(1);
base::TimeDelta cooldown_interval =
monitor_->GetCooldownInterval() + base::TimeDelta::FromSeconds(1);
monitor_->SimulateNearOom();
// The first detection should happen when |interval| is passed.
TestNearOomObserver observer1(monitor_.get());
task_runner_->FastForwardBy(interval);
EXPECT_TRUE(observer1.is_detected());
observer1.Unsubscribe();
// After a detection, the next detection shouldn't happen until
// |cooldown_interval| is passed.
TestNearOomObserver observer2(monitor_.get());
task_runner_->FastForwardBy(interval);
EXPECT_FALSE(observer2.is_detected());
task_runner_->FastForwardBy(cooldown_interval);
EXPECT_TRUE(observer2.is_detected());
observer2.Unsubscribe();
}