Roll src/third_party/WebKit eac3800:0237a66 (svn 202606:202607)
[chromium-blink-merge.git] / chrome / browser / memory / oom_priority_manager_browsertest.cc
blob6441d6747ec3b7b3877684f18819dd4bc16cef86
1 // Copyright (c) 2012 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.
5 #include "base/command_line.h"
6 #include "base/memory/memory_pressure_listener.h"
7 #include "chrome/browser/browser_process.h"
8 #include "chrome/browser/memory/oom_priority_manager.h"
9 #include "chrome/browser/ui/browser.h"
10 #include "chrome/browser/ui/browser_commands.h"
11 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
12 #include "chrome/browser/ui/tabs/tab_discard_state.h"
13 #include "chrome/browser/ui/tabs/tab_strip_model.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/url_constants.h"
16 #include "chrome/test/base/in_process_browser_test.h"
17 #include "content/public/browser/notification_service.h"
18 #include "content/public/browser/notification_types.h"
19 #include "content/public/test/test_utils.h"
20 #include "url/gurl.h"
22 using content::OpenURLParams;
24 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
26 namespace memory {
27 namespace {
29 class OomPriorityManagerTest : public InProcessBrowserTest {
30 public:
31 // Tab discarding is enabled by default on CrOS, on other platforms, force it
32 // by setting the command line flag.
33 void SetUpCommandLine(base::CommandLine* command_line) override {
34 #if !defined(OS_CHROMEOS)
35 command_line->AppendSwitch(switches::kEnableTabDiscarding);
36 #endif
41 IN_PROC_BROWSER_TEST_F(OomPriorityManagerTest, OomPriorityManagerBasics) {
42 using content::WindowedNotificationObserver;
43 OomPriorityManager* oom_priority_manager =
44 g_browser_process->GetOomPriorityManager();
45 ASSERT_TRUE(oom_priority_manager);
46 EXPECT_FALSE(oom_priority_manager->recent_tab_discard());
48 // Get three tabs open.
49 WindowedNotificationObserver load1(
50 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
51 content::NotificationService::AllSources());
52 OpenURLParams open1(GURL(chrome::kChromeUIAboutURL), content::Referrer(),
53 CURRENT_TAB, ui::PAGE_TRANSITION_TYPED, false);
54 browser()->OpenURL(open1);
55 load1.Wait();
57 WindowedNotificationObserver load2(
58 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
59 content::NotificationService::AllSources());
60 OpenURLParams open2(GURL(chrome::kChromeUICreditsURL), content::Referrer(),
61 NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_TYPED, false);
62 browser()->OpenURL(open2);
63 load2.Wait();
65 WindowedNotificationObserver load3(
66 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
67 content::NotificationService::AllSources());
68 OpenURLParams open3(GURL(chrome::kChromeUITermsURL), content::Referrer(),
69 NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_TYPED, false);
70 browser()->OpenURL(open3);
71 load3.Wait();
73 auto tsm = browser()->tab_strip_model();
74 EXPECT_EQ(3, tsm->count());
76 // Navigate the current (third) tab to a different URL, so we can test
77 // back/forward later.
78 WindowedNotificationObserver load4(
79 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
80 content::NotificationService::AllSources());
81 OpenURLParams open4(GURL(chrome::kChromeUIVersionURL), content::Referrer(),
82 CURRENT_TAB, ui::PAGE_TRANSITION_TYPED, false);
83 browser()->OpenURL(open4);
84 load4.Wait();
86 // Navigate the third tab again, such that we have three navigation entries.
87 WindowedNotificationObserver load5(
88 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
89 content::NotificationService::AllSources());
90 OpenURLParams open5(GURL("chrome://dns"), content::Referrer(), CURRENT_TAB,
91 ui::PAGE_TRANSITION_TYPED, false);
92 browser()->OpenURL(open5);
93 load5.Wait();
95 EXPECT_EQ(3, tsm->count());
97 // Discard a tab. It should kill the first tab, since it was the oldest
98 // and was not selected.
99 EXPECT_TRUE(oom_priority_manager->DiscardTab());
100 EXPECT_EQ(3, tsm->count());
101 EXPECT_TRUE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(0)));
102 EXPECT_FALSE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(1)));
103 EXPECT_FALSE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(2)));
104 EXPECT_TRUE(oom_priority_manager->recent_tab_discard());
106 // Run discard again, make sure it kills the second tab.
107 EXPECT_TRUE(oom_priority_manager->DiscardTab());
108 EXPECT_EQ(3, tsm->count());
109 EXPECT_TRUE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(0)));
110 EXPECT_TRUE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(1)));
111 EXPECT_FALSE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(2)));
113 // Kill the third tab. It should not kill the last tab, since it is active
114 // tab.
115 EXPECT_FALSE(oom_priority_manager->DiscardTab());
116 EXPECT_TRUE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(0)));
117 EXPECT_TRUE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(1)));
118 EXPECT_FALSE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(2)));
120 // Kill the third tab after making second tab active.
121 tsm->ActivateTabAt(1, true);
122 EXPECT_EQ(1, tsm->active_index());
123 EXPECT_FALSE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(1)));
124 tsm->DiscardWebContentsAt(2);
125 EXPECT_TRUE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(2)));
127 // Force creation of the FindBarController.
128 browser()->GetFindBarController();
130 // Select the first tab. It should reload.
131 WindowedNotificationObserver reload1(
132 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
133 content::NotificationService::AllSources());
134 chrome::SelectNumberedTab(browser(), 0);
135 reload1.Wait();
136 // Make sure the FindBarController gets the right WebContents.
137 EXPECT_EQ(browser()->GetFindBarController()->web_contents(),
138 tsm->GetActiveWebContents());
139 EXPECT_EQ(0, tsm->active_index());
140 EXPECT_FALSE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(0)));
141 EXPECT_FALSE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(1)));
142 EXPECT_TRUE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(2)));
144 // Select the third tab. It should reload.
145 WindowedNotificationObserver reload2(
146 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
147 content::NotificationService::AllSources());
148 chrome::SelectNumberedTab(browser(), 2);
149 reload2.Wait();
150 EXPECT_EQ(2, tsm->active_index());
151 EXPECT_FALSE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(0)));
152 EXPECT_FALSE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(1)));
153 EXPECT_FALSE(TabDiscardState::IsDiscarded(tsm->GetWebContentsAt(2)));
155 // Navigate the third tab back twice. We used to crash here due to
156 // crbug.com/121373.
157 EXPECT_TRUE(chrome::CanGoBack(browser()));
158 EXPECT_FALSE(chrome::CanGoForward(browser()));
159 WindowedNotificationObserver back1(
160 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
161 content::NotificationService::AllSources());
162 chrome::GoBack(browser(), CURRENT_TAB);
163 back1.Wait();
164 EXPECT_TRUE(chrome::CanGoBack(browser()));
165 EXPECT_TRUE(chrome::CanGoForward(browser()));
166 WindowedNotificationObserver back2(
167 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
168 content::NotificationService::AllSources());
169 chrome::GoBack(browser(), CURRENT_TAB);
170 back2.Wait();
171 EXPECT_FALSE(chrome::CanGoBack(browser()));
172 EXPECT_TRUE(chrome::CanGoForward(browser()));
175 // Test that the MemoryPressureListener event is properly triggering a tab
176 // discard upon |MEMORY_PRESSURE_LEVEL_CRITICAL| event.
177 IN_PROC_BROWSER_TEST_F(OomPriorityManagerTest, OomPressureListener) {
178 OomPriorityManager* oom_priority_manager =
179 g_browser_process->GetOomPriorityManager();
180 ASSERT_TRUE(oom_priority_manager);
182 // Get three tabs open.
183 content::WindowedNotificationObserver load1(
184 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
185 content::NotificationService::AllSources());
186 OpenURLParams open1(GURL(chrome::kChromeUIAboutURL), content::Referrer(),
187 CURRENT_TAB, ui::PAGE_TRANSITION_TYPED, false);
188 browser()->OpenURL(open1);
189 load1.Wait();
191 content::WindowedNotificationObserver load2(
192 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
193 content::NotificationService::AllSources());
194 OpenURLParams open2(GURL(chrome::kChromeUICreditsURL), content::Referrer(),
195 NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_TYPED, false);
196 browser()->OpenURL(open2);
197 load2.Wait();
198 EXPECT_FALSE(oom_priority_manager->recent_tab_discard());
200 // Nothing should happen with a moderate memory pressure event.
201 base::MemoryPressureListener::NotifyMemoryPressure(
202 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
203 EXPECT_FALSE(oom_priority_manager->recent_tab_discard());
205 // A critical memory pressure event should discard a tab.
206 base::MemoryPressureListener::NotifyMemoryPressure(
207 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
208 // Coming here, an asynchronous operation will collect system stats. Once in,
209 // a tab should get discarded. As such we need to give it 10s time to discard.
210 const int kTimeoutTimeInMS = 10000;
211 const int kIntervalTimeInMS = 5;
212 int timeout = kTimeoutTimeInMS / kIntervalTimeInMS;
213 while (--timeout) {
214 base::PlatformThread::Sleep(
215 base::TimeDelta::FromMilliseconds(kIntervalTimeInMS));
216 base::RunLoop().RunUntilIdle();
217 if (oom_priority_manager->recent_tab_discard())
218 break;
220 EXPECT_TRUE(oom_priority_manager->recent_tab_discard());
223 } // namespace
224 } // namespace memory
226 #endif // OS_WIN || OS_CHROMEOS