OLD | NEW |
| (Empty) |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/browser/memory/memory_coordinator.h" | |
6 | |
7 #include "base/memory/memory_pressure_monitor.h" | |
8 #include "base/message_loop/message_loop.h" | |
9 #include "base/run_loop.h" | |
10 #include "mojo/public/cpp/bindings/binding.h" | |
11 | |
12 #include "testing/gtest/include/gtest/gtest.h" | |
13 | |
14 namespace content { | |
15 | |
16 namespace { | |
17 | |
18 void RunUntilIdle() { | |
19 base::RunLoop loop; | |
20 loop.RunUntilIdle(); | |
21 } | |
22 | |
23 } // namespace | |
24 | |
25 // A mock ChildMemoryCoordinator, for testing interaction between MC and CMC. | |
26 class MockChildMemoryCoordinator : public mojom::ChildMemoryCoordinator { | |
27 public: | |
28 MockChildMemoryCoordinator() | |
29 : state_(mojom::MemoryState::NORMAL), | |
30 on_state_change_calls_(0) {} | |
31 | |
32 ~MockChildMemoryCoordinator() override {} | |
33 | |
34 void OnStateChange(mojom::MemoryState state) override { | |
35 state_ = state; | |
36 ++on_state_change_calls_; | |
37 } | |
38 | |
39 mojom::MemoryState state() const { return state_; } | |
40 int on_state_change_calls() const { return on_state_change_calls_; } | |
41 | |
42 private: | |
43 mojom::MemoryState state_; | |
44 int on_state_change_calls_; | |
45 }; | |
46 | |
47 // A MemoryCoordinator that can be directly constructed. | |
48 class TestMemoryCoordinator : public MemoryCoordinator { | |
49 public: | |
50 // Mojo machinery for wrapping a mock ChildMemoryCoordinator. | |
51 struct Child { | |
52 Child(mojom::ChildMemoryCoordinatorPtr* cmc_ptr) : cmc_binding(&cmc) { | |
53 cmc_binding.Bind(mojo::GetProxy(cmc_ptr)); | |
54 RunUntilIdle(); | |
55 } | |
56 | |
57 MockChildMemoryCoordinator cmc; | |
58 mojo::Binding<mojom::ChildMemoryCoordinator> cmc_binding; | |
59 }; | |
60 | |
61 TestMemoryCoordinator() {} | |
62 ~TestMemoryCoordinator() override {} | |
63 | |
64 using MemoryCoordinator::OnConnectionError; | |
65 | |
66 MockChildMemoryCoordinator* CreateChildMemoryCoordinator( | |
67 int process_id) { | |
68 mojom::ChildMemoryCoordinatorPtr cmc_ptr; | |
69 children_.push_back(std::unique_ptr<Child>(new Child(&cmc_ptr))); | |
70 AddChildForTesting(process_id, std::move(cmc_ptr)); | |
71 return &children_.back()->cmc; | |
72 } | |
73 | |
74 // Wrapper of MemoryCoordinator::SetMemoryState that also calls RunUntilIdle. | |
75 bool SetChildMemoryState( | |
76 int render_process_id, mojom::MemoryState memory_state) { | |
77 bool result = MemoryCoordinator::SetChildMemoryState( | |
78 render_process_id, memory_state); | |
79 RunUntilIdle(); | |
80 return result; | |
81 } | |
82 | |
83 std::vector<std::unique_ptr<Child>> children_; | |
84 }; | |
85 | |
86 // Test fixture. | |
87 class MemoryCoordinatorTest : public testing::Test { | |
88 private: | |
89 // Needed for mojo. | |
90 base::MessageLoop message_loop_; | |
91 }; | |
92 | |
93 TEST_F(MemoryCoordinatorTest, ChildRemovedOnConnectionError) { | |
94 TestMemoryCoordinator mc; | |
95 mc.CreateChildMemoryCoordinator(1); | |
96 ASSERT_EQ(1u, mc.children().size()); | |
97 mc.OnConnectionError(1); | |
98 EXPECT_EQ(0u, mc.children().size()); | |
99 } | |
100 | |
101 TEST_F(MemoryCoordinatorTest, SetMemoryStateFailsInvalidState) { | |
102 TestMemoryCoordinator mc; | |
103 auto cmc1 = mc.CreateChildMemoryCoordinator(1); | |
104 | |
105 EXPECT_FALSE(mc.SetChildMemoryState(1, mojom::MemoryState::UNKNOWN)); | |
106 EXPECT_EQ(0, cmc1->on_state_change_calls()); | |
107 } | |
108 | |
109 TEST_F(MemoryCoordinatorTest, SetMemoryStateFailsInvalidRenderer) { | |
110 TestMemoryCoordinator mc; | |
111 auto cmc1 = mc.CreateChildMemoryCoordinator(1); | |
112 | |
113 EXPECT_FALSE(mc.SetChildMemoryState(2, mojom::MemoryState::THROTTLED)); | |
114 EXPECT_EQ(0, cmc1->on_state_change_calls()); | |
115 } | |
116 | |
117 TEST_F(MemoryCoordinatorTest, SetMemoryStateNotDeliveredNop) { | |
118 TestMemoryCoordinator mc; | |
119 auto cmc1 = mc.CreateChildMemoryCoordinator(1); | |
120 | |
121 EXPECT_FALSE(mc.SetChildMemoryState(2, mojom::MemoryState::NORMAL)); | |
122 EXPECT_EQ(0, cmc1->on_state_change_calls()); | |
123 } | |
124 | |
125 TEST_F(MemoryCoordinatorTest, SetMemoryStateDelivered) { | |
126 TestMemoryCoordinator mc; | |
127 auto cmc1 = mc.CreateChildMemoryCoordinator(1); | |
128 auto cmc2 = mc.CreateChildMemoryCoordinator(2); | |
129 | |
130 EXPECT_TRUE(mc.SetChildMemoryState(1, mojom::MemoryState::THROTTLED)); | |
131 EXPECT_EQ(1, cmc1->on_state_change_calls()); | |
132 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc1->state()); | |
133 | |
134 EXPECT_TRUE(mc.SetChildMemoryState(2, mojom::MemoryState::SUSPENDED)); | |
135 EXPECT_EQ(1, cmc2->on_state_change_calls()); | |
136 // Child processes are considered as visible (foreground) by default, | |
137 // and visible ones won't be suspended but throttled. | |
138 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc2->state()); | |
139 } | |
140 | |
141 TEST_F(MemoryCoordinatorTest, SetChildMemoryState) { | |
142 TestMemoryCoordinator mc; | |
143 auto cmc = mc.CreateChildMemoryCoordinator(1); | |
144 auto iter = mc.children().find(1); | |
145 ASSERT_TRUE(iter != mc.children().end()); | |
146 | |
147 // Foreground | |
148 iter->second.is_visible = true; | |
149 EXPECT_TRUE(mc.SetChildMemoryState(1, mojom::MemoryState::NORMAL)); | |
150 EXPECT_EQ(mojom::MemoryState::NORMAL, cmc->state()); | |
151 EXPECT_TRUE(mc.SetChildMemoryState(1, mojom::MemoryState::THROTTLED)); | |
152 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc->state()); | |
153 EXPECT_TRUE(mc.SetChildMemoryState(1, mojom::MemoryState::SUSPENDED)); | |
154 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc->state()); | |
155 | |
156 // Background | |
157 iter->second.is_visible = false; | |
158 EXPECT_TRUE(mc.SetChildMemoryState(1, mojom::MemoryState::NORMAL)); | |
159 #if defined(OS_ANDROID) | |
160 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc->state()); | |
161 #else | |
162 EXPECT_EQ(mojom::MemoryState::NORMAL, cmc->state()); | |
163 #endif | |
164 EXPECT_TRUE(mc.SetChildMemoryState(1, mojom::MemoryState::THROTTLED)); | |
165 EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc->state()); | |
166 EXPECT_TRUE(mc.SetChildMemoryState(1, mojom::MemoryState::SUSPENDED)); | |
167 EXPECT_EQ(mojom::MemoryState::SUSPENDED, cmc->state()); | |
168 } | |
169 | |
170 } // namespace content | |
OLD | NEW |