Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / profiles / host_zoom_map_browsertest.cc
blobe099154e9dc911193d0cc0f07f841cf32aa43661
1 // Copyright 2014 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 "content/public/browser/host_zoom_map.h"
7 #include <algorithm>
8 #include <string>
9 #include <vector>
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_util.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/path_service.h"
18 #include "base/prefs/pref_service.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/values.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/profiles/profile_impl.h"
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/tabs/tab_strip_model.h"
25 #include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h"
26 #include "chrome/common/chrome_constants.h"
27 #include "chrome/common/chrome_paths.h"
28 #include "chrome/common/pref_names.h"
29 #include "chrome/common/url_constants.h"
30 #include "chrome/test/base/in_process_browser_test.h"
31 #include "chrome/test/base/testing_profile.h"
32 #include "chrome/test/base/ui_test_utils.h"
33 #include "components/signin/core/common/profile_management_switches.h"
34 #include "components/signin/core/common/signin_switches.h"
35 #include "components/ui/zoom/page_zoom.h"
36 #include "components/ui/zoom/zoom_event_manager.h"
37 #include "content/public/test/test_utils.h"
38 #include "net/dns/mock_host_resolver.h"
39 #include "net/test/embedded_test_server/embedded_test_server.h"
40 #include "net/test/embedded_test_server/http_response.h"
41 #include "testing/gmock/include/gmock/gmock.h"
42 #include "url/gurl.h"
44 using content::HostZoomMap;
46 namespace {
48 class ZoomLevelChangeObserver {
49 public:
50 explicit ZoomLevelChangeObserver(content::BrowserContext* context)
51 : message_loop_runner_(new content::MessageLoopRunner) {
52 subscription_ = ui_zoom::ZoomEventManager::GetForBrowserContext(context)
53 ->AddZoomLevelChangedCallback(base::Bind(
54 &ZoomLevelChangeObserver::OnZoomLevelChanged,
55 base::Unretained(this)));
58 void BlockUntilZoomLevelForHostHasChanged(const std::string& host) {
59 while (!std::count(changed_hosts_.begin(), changed_hosts_.end(), host)) {
60 message_loop_runner_->Run();
61 message_loop_runner_ = new content::MessageLoopRunner;
63 changed_hosts_.clear();
66 private:
67 void OnZoomLevelChanged(const content::HostZoomMap::ZoomLevelChange& change) {
68 changed_hosts_.push_back(change.host);
69 message_loop_runner_->Quit();
72 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
73 std::vector<std::string> changed_hosts_;
74 scoped_ptr<content::HostZoomMap::Subscription> subscription_;
76 DISALLOW_COPY_AND_ASSIGN(ZoomLevelChangeObserver);
79 } // namespace
81 class HostZoomMapBrowserTest : public InProcessBrowserTest {
82 public:
83 HostZoomMapBrowserTest() {}
85 protected:
86 void SetDefaultZoomLevel(double level) {
87 browser()->profile()->GetZoomLevelPrefs()->SetDefaultZoomLevelPref(level);
90 double GetZoomLevel(const GURL& url) {
91 content::HostZoomMap* host_zoom_map = static_cast<content::HostZoomMap*>(
92 content::HostZoomMap::GetDefaultForBrowserContext(
93 browser()->profile()));
94 return host_zoom_map->GetZoomLevelForHostAndScheme(url.scheme(),
95 url.host());
98 std::vector<std::string> GetHostsWithZoomLevels() {
99 typedef content::HostZoomMap::ZoomLevelVector ZoomLevelVector;
100 content::HostZoomMap* host_zoom_map = static_cast<content::HostZoomMap*>(
101 content::HostZoomMap::GetDefaultForBrowserContext(
102 browser()->profile()));
103 content::HostZoomMap::ZoomLevelVector zoom_levels =
104 host_zoom_map->GetAllZoomLevels();
105 std::vector<std::string> results;
106 for (ZoomLevelVector::const_iterator it = zoom_levels.begin();
107 it != zoom_levels.end(); ++it)
108 results.push_back(it->host);
109 return results;
112 std::vector<std::string> GetHostsWithZoomLevelsFromPrefs() {
113 PrefService* prefs = browser()->profile()->GetPrefs();
114 const base::DictionaryValue* dictionaries =
115 prefs->GetDictionary(prefs::kPartitionPerHostZoomLevels);
116 const base::DictionaryValue* values = NULL;
117 std::string partition_key =
118 chrome::ChromeZoomLevelPrefs::GetHashForTesting(base::FilePath());
119 dictionaries->GetDictionary(partition_key, &values);
120 std::vector<std::string> results;
121 if (values) {
122 for (base::DictionaryValue::Iterator it(*values);
123 !it.IsAtEnd(); it.Advance())
124 results.push_back(it.key());
126 return results;
129 GURL ConstructTestServerURL(const char* url_template) {
130 return GURL(base::StringPrintf(
131 url_template, embedded_test_server()->port()));
134 private:
135 scoped_ptr<net::test_server::HttpResponse> HandleRequest(
136 const net::test_server::HttpRequest& request) {
137 return scoped_ptr<net::test_server::HttpResponse>(
138 new net::test_server::BasicHttpResponse);
141 // BrowserTestBase:
142 void SetUpOnMainThread() override {
143 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
144 embedded_test_server()->RegisterRequestHandler(base::Bind(
145 &HostZoomMapBrowserTest::HandleRequest, base::Unretained(this)));
146 host_resolver()->AddRule("*", "127.0.0.1");
149 DISALLOW_COPY_AND_ASSIGN(HostZoomMapBrowserTest);
152 #define PARTITION_KEY_PLACEHOLDER "NNN"
154 class HostZoomMapBrowserTestWithPrefs : public HostZoomMapBrowserTest {
155 public:
156 explicit HostZoomMapBrowserTestWithPrefs(const std::string& prefs_data)
157 : prefs_data_(prefs_data) {}
159 private:
160 // InProcessBrowserTest:
161 bool SetUpUserDataDirectory() override {
162 std::replace(prefs_data_.begin(), prefs_data_.end(), '\'', '\"');
163 // It seems the hash functions on different platforms can return different
164 // values for the same input, so make sure we test with the hash appropriate
165 // for the platform.
166 std::string hash_string =
167 chrome::ChromeZoomLevelPrefs::GetHashForTesting(base::FilePath());
168 std::string partition_key_placeholder(PARTITION_KEY_PLACEHOLDER);
169 size_t start_index;
170 while ((start_index = prefs_data_.find(partition_key_placeholder)) !=
171 std::string::npos) {
172 prefs_data_.replace(
173 start_index, partition_key_placeholder.size(), hash_string);
176 base::FilePath user_data_directory, path_to_prefs;
177 PathService::Get(chrome::DIR_USER_DATA, &user_data_directory);
178 path_to_prefs = user_data_directory
179 .AppendASCII(TestingProfile::kTestUserProfileDir)
180 .Append(chrome::kPreferencesFilename);
181 base::CreateDirectory(path_to_prefs.DirName());
182 base::WriteFile(
183 path_to_prefs, prefs_data_.c_str(), prefs_data_.size());
184 return true;
187 std::string prefs_data_;
189 DISALLOW_COPY_AND_ASSIGN(HostZoomMapBrowserTestWithPrefs);
192 // Zoom-related preferences demonstrating the two problems that
193 // could be caused by the bug. They incorrectly contain a per-host
194 // zoom level for the empty host; and a value for 'host1' that only
195 // differs from the default by epsilon. Neither should have been
196 // persisted.
197 const char kSanitizationTestPrefs[] =
198 "{'partition': {"
199 " 'default_zoom_level': { '" PARTITION_KEY_PLACEHOLDER "': 1.2 },"
200 " 'per_host_zoom_levels': {"
201 " '" PARTITION_KEY_PLACEHOLDER "': {"
202 " '': 1.1, 'host1': 1.20001, 'host2': 1.3 }"
203 " }"
204 "}}";
206 #undef PARTITION_KEY_PLACEHOLDER
208 class HostZoomMapSanitizationBrowserTest
209 : public HostZoomMapBrowserTestWithPrefs {
210 public:
211 HostZoomMapSanitizationBrowserTest()
212 : HostZoomMapBrowserTestWithPrefs(kSanitizationTestPrefs) {}
214 private:
215 DISALLOW_COPY_AND_ASSIGN(HostZoomMapSanitizationBrowserTest);
218 // Regression test for crbug.com/437392
219 IN_PROC_BROWSER_TEST_F(HostZoomMapBrowserTest, ZoomEventsWorkForOffTheRecord) {
220 GURL test_url(url::kAboutBlankURL);
221 std::string test_host(test_url.host());
222 std::string test_scheme(test_url.scheme());
223 Browser* incognito_browser =
224 OpenURLOffTheRecord(browser()->profile(), test_url);
226 content::WebContents* web_contents =
227 incognito_browser->tab_strip_model()->GetActiveWebContents();
229 content::BrowserContext* context = web_contents->GetBrowserContext();
230 EXPECT_TRUE(context->IsOffTheRecord());
231 ZoomLevelChangeObserver observer(context);
232 HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents);
234 double new_zoom_level =
235 host_zoom_map->GetZoomLevelForHostAndScheme(test_scheme, test_host) + 0.5;
236 host_zoom_map->SetZoomLevelForHostAndScheme(test_scheme, test_host,
237 new_zoom_level);
238 observer.BlockUntilZoomLevelForHostHasChanged(test_host);
239 EXPECT_EQ(new_zoom_level, host_zoom_map->GetZoomLevelForHostAndScheme(
240 test_scheme, test_host));
243 IN_PROC_BROWSER_TEST_F(
244 HostZoomMapBrowserTest,
245 WebviewBasedSigninUsesDefaultStoragePartitionForEmbedder) {
246 GURL test_url = ConstructTestServerURL(chrome::kChromeUIChromeSigninURL);
247 std::string test_host(test_url.host());
248 std::string test_scheme(test_url.scheme());
249 ui_test_utils::NavigateToURL(browser(), test_url);
251 content::WebContents* web_contents =
252 browser()->tab_strip_model()->GetActiveWebContents();
254 HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents);
256 // For the webview based sign-in code, the sign in page uses the default host
257 // zoom map.
258 HostZoomMap* default_profile_host_zoom_map =
259 HostZoomMap::GetDefaultForBrowserContext(browser()->profile());
260 // Since ChromeOS still uses IFrame-based signin, we should expect the
261 // storage partition to be different if Webview signin is not enabled.
262 if (switches::IsEnableWebviewBasedSignin())
263 EXPECT_EQ(host_zoom_map, default_profile_host_zoom_map);
264 else
265 EXPECT_NE(host_zoom_map, default_profile_host_zoom_map);
268 class HostZoomMapIframeSigninBrowserTest : public HostZoomMapBrowserTest {
269 public:
270 void SetUpCommandLine(base::CommandLine* command_line) override {
271 command_line->AppendSwitch(switches::kEnableIframeBasedSignin);
275 // Regression test for crbug.com/435017.
276 IN_PROC_BROWSER_TEST_F(HostZoomMapIframeSigninBrowserTest,
277 EventsForNonDefaultStoragePartition) {
278 ZoomLevelChangeObserver observer(browser()->profile());
279 // TODO(wjmaclean): Make this test more general by implementing a way to
280 // force a generic URL to be loaded in a non-default storage partition. This
281 // test currently relies on the signin page being loaded into a non-default
282 // storage partition (and verifies this is the case), but ultimately it would
283 // be better not to rely on what the signin page is doing.
284 GURL test_url = ConstructTestServerURL(chrome::kChromeUIChromeSigninURL);
285 std::string test_host(test_url.host());
286 std::string test_scheme(test_url.scheme());
287 ui_test_utils::NavigateToURL(browser(), test_url);
289 content::WebContents* web_contents =
290 browser()->tab_strip_model()->GetActiveWebContents();
292 // We are forcing non-webview based signin, so we expect the signin page to
293 // be in a different storage partition, and hence a different HostZoomMap.
294 HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents);
296 EXPECT_FALSE(switches::IsEnableWebviewBasedSignin());
297 HostZoomMap* default_profile_host_zoom_map =
298 HostZoomMap::GetDefaultForBrowserContext(browser()->profile());
299 EXPECT_NE(host_zoom_map, default_profile_host_zoom_map);
301 double new_zoom_level =
302 host_zoom_map->GetZoomLevelForHostAndScheme(test_scheme, test_host) + 0.5;
303 host_zoom_map->SetZoomLevelForHostAndScheme(test_scheme, test_host,
304 new_zoom_level);
305 observer.BlockUntilZoomLevelForHostHasChanged(test_host);
306 EXPECT_EQ(new_zoom_level, host_zoom_map->GetZoomLevelForHostAndScheme(
307 test_scheme, test_host));
310 // Regression test for crbug.com/364399.
311 IN_PROC_BROWSER_TEST_F(HostZoomMapBrowserTest, ToggleDefaultZoomLevel) {
312 const double default_zoom_level = content::ZoomFactorToZoomLevel(1.5);
314 const char kTestURLTemplate1[] = "http://host1:%u/";
315 const char kTestURLTemplate2[] = "http://host2:%u/";
317 ZoomLevelChangeObserver observer(browser()->profile());
319 GURL test_url1 = ConstructTestServerURL(kTestURLTemplate1);
320 ui_test_utils::NavigateToURL(browser(), test_url1);
322 SetDefaultZoomLevel(default_zoom_level);
323 observer.BlockUntilZoomLevelForHostHasChanged(test_url1.host());
324 EXPECT_TRUE(
325 content::ZoomValuesEqual(default_zoom_level, GetZoomLevel(test_url1)));
327 GURL test_url2 = ConstructTestServerURL(kTestURLTemplate2);
328 ui_test_utils::NavigateToURLWithDisposition(
329 browser(), test_url2, NEW_FOREGROUND_TAB,
330 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
331 EXPECT_TRUE(
332 content::ZoomValuesEqual(default_zoom_level, GetZoomLevel(test_url2)));
334 content::WebContents* web_contents =
335 browser()->tab_strip_model()->GetActiveWebContents();
336 ui_zoom::PageZoom::Zoom(web_contents, content::PAGE_ZOOM_OUT);
337 observer.BlockUntilZoomLevelForHostHasChanged(test_url2.host());
338 EXPECT_FALSE(
339 content::ZoomValuesEqual(default_zoom_level, GetZoomLevel(test_url2)));
341 ui_zoom::PageZoom::Zoom(web_contents, content::PAGE_ZOOM_IN);
342 observer.BlockUntilZoomLevelForHostHasChanged(test_url2.host());
343 EXPECT_TRUE(
344 content::ZoomValuesEqual(default_zoom_level, GetZoomLevel(test_url2)));
346 // Now both tabs should be at the default zoom level, so there should not be
347 // any per-host values saved either to Pref, or internally in HostZoomMap.
348 EXPECT_TRUE(GetHostsWithZoomLevels().empty());
349 EXPECT_TRUE(GetHostsWithZoomLevelsFromPrefs().empty());
352 // Test that garbage data from crbug.com/364399 is cleared up on startup.
353 IN_PROC_BROWSER_TEST_F(HostZoomMapSanitizationBrowserTest, ClearOnStartup) {
354 EXPECT_THAT(GetHostsWithZoomLevels(), testing::ElementsAre("host2"));
355 EXPECT_THAT(GetHostsWithZoomLevelsFromPrefs(), testing::ElementsAre("host2"));
358 // In this case we migrate the zoom level data from the profile prefs.
359 const char kMigrationTestPrefs[] =
360 "{'profile': {"
361 " 'default_zoom_level': 1.2,"
362 " 'per_host_zoom_levels': {'': 1.1, 'host1': 1.20001, 'host2': "
363 "1.3}"
364 "}}";
366 class HostZoomMapMigrationBrowserTest : public HostZoomMapBrowserTestWithPrefs {
367 public:
368 HostZoomMapMigrationBrowserTest()
369 : HostZoomMapBrowserTestWithPrefs(kMigrationTestPrefs) {}
371 static const double kOriginalDefaultZoomLevel;
373 private:
374 DISALLOW_COPY_AND_ASSIGN(HostZoomMapMigrationBrowserTest);
377 const double HostZoomMapMigrationBrowserTest::kOriginalDefaultZoomLevel = 1.2;
379 // This test is the same as HostZoomMapSanitizationBrowserTest, except that the
380 // zoom level data is loaded from the profile prefs, transfered to the
381 // zoom-level prefs, and we verify that the profile zoom level prefs are
382 // erased in the process. We also test that changes to the host zoom map and the
383 // default zoom level don't propagate back to the profile prefs.
384 IN_PROC_BROWSER_TEST_F(HostZoomMapMigrationBrowserTest,
385 MigrateProfileZoomPreferences) {
386 EXPECT_THAT(GetHostsWithZoomLevels(), testing::ElementsAre("host2"));
387 EXPECT_THAT(GetHostsWithZoomLevelsFromPrefs(), testing::ElementsAre("host2"));
389 PrefService* profile_prefs =
390 browser()->profile()->GetPrefs();
391 chrome::ChromeZoomLevelPrefs* zoom_level_prefs =
392 browser()->profile()->GetZoomLevelPrefs();
393 // Make sure that the profile pref for default zoom level has been set to
394 // its default value of 0.0.
395 EXPECT_EQ(0.0, profile_prefs->GetDouble(prefs::kDefaultZoomLevelDeprecated));
396 EXPECT_EQ(kOriginalDefaultZoomLevel,
397 zoom_level_prefs->GetDefaultZoomLevelPref());
399 // Make sure that the profile prefs for per-host zoom levels are erased.
401 const base::DictionaryValue* profile_host_zoom_dictionary =
402 profile_prefs->GetDictionary(prefs::kPerHostZoomLevelsDeprecated);
403 EXPECT_EQ(0UL, profile_host_zoom_dictionary->size());
406 ZoomLevelChangeObserver observer(browser()->profile());
407 content::HostZoomMap* host_zoom_map = static_cast<content::HostZoomMap*>(
408 content::HostZoomMap::GetDefaultForBrowserContext(
409 browser()->profile()));
411 // Make sure that a change to a host zoom level doesn't propagate to the
412 // profile prefs.
413 std::string host3("host3");
414 host_zoom_map->SetZoomLevelForHost(host3, 1.3);
415 observer.BlockUntilZoomLevelForHostHasChanged(host3);
416 EXPECT_THAT(GetHostsWithZoomLevelsFromPrefs(),
417 testing::ElementsAre("host2", host3));
419 const base::DictionaryValue* profile_host_zoom_dictionary =
420 profile_prefs->GetDictionary(prefs::kPerHostZoomLevelsDeprecated);
421 EXPECT_EQ(0UL, profile_host_zoom_dictionary->size());
424 // Make sure a change to the default zoom level doesn't propagate to the
425 // profile prefs.
427 // First, we need a host at the default zoom level to respond when the
428 // default zoom level changes.
429 const double kNewDefaultZoomLevel = 1.5;
430 GURL test_url = ConstructTestServerURL("http://host4:%u/");
431 ui_test_utils::NavigateToURL(browser(), test_url);
432 EXPECT_TRUE(content::ZoomValuesEqual(kOriginalDefaultZoomLevel,
433 GetZoomLevel(test_url)));
435 // Change the default zoom level and observe.
436 SetDefaultZoomLevel(kNewDefaultZoomLevel);
437 observer.BlockUntilZoomLevelForHostHasChanged(test_url.host());
438 EXPECT_TRUE(
439 content::ZoomValuesEqual(kNewDefaultZoomLevel, GetZoomLevel(test_url)));
440 EXPECT_EQ(kNewDefaultZoomLevel, zoom_level_prefs->GetDefaultZoomLevelPref());
441 EXPECT_EQ(0.0, profile_prefs->GetDouble(prefs::kDefaultZoomLevelDeprecated));
444 // Test four things:
445 // 1. Host zoom maps of parent profile and child profile are different.
446 // 2. Child host zoom map inherits zoom level at construction.
447 // 3. Change of zoom level doesn't propagate from child to parent.
448 // 4. Change of zoom level propagates from parent to child.
449 IN_PROC_BROWSER_TEST_F(HostZoomMapBrowserTest,
450 OffTheRecordProfileHostZoomMap) {
451 // Constants for test case.
452 const std::string host("example.com");
453 const double zoom_level_25 = 2.5;
454 const double zoom_level_30 = 3.0;
455 const double zoom_level_40 = 4.0;
457 Profile* parent_profile = browser()->profile();
458 Profile* child_profile =
459 static_cast<ProfileImpl*>(parent_profile)->GetOffTheRecordProfile();
460 HostZoomMap* parent_zoom_map =
461 HostZoomMap::GetDefaultForBrowserContext(parent_profile);
462 ASSERT_TRUE(parent_zoom_map);
464 parent_zoom_map->SetZoomLevelForHost(host, zoom_level_25);
465 ASSERT_EQ(parent_zoom_map->GetZoomLevelForHostAndScheme("http", host),
466 zoom_level_25);
468 // Prepare child host zoom map.
469 HostZoomMap* child_zoom_map =
470 HostZoomMap::GetDefaultForBrowserContext(child_profile);
471 ASSERT_TRUE(child_zoom_map);
473 // Verify.
474 EXPECT_NE(parent_zoom_map, child_zoom_map);
476 EXPECT_EQ(parent_zoom_map->GetZoomLevelForHostAndScheme("http", host),
477 child_zoom_map->GetZoomLevelForHostAndScheme("http", host)) <<
478 "Child must inherit from parent.";
480 child_zoom_map->SetZoomLevelForHost(host, zoom_level_30);
481 ASSERT_EQ(
482 child_zoom_map->GetZoomLevelForHostAndScheme("http", host),
483 zoom_level_30);
485 EXPECT_NE(parent_zoom_map->GetZoomLevelForHostAndScheme("http", host),
486 child_zoom_map->GetZoomLevelForHostAndScheme("http", host)) <<
487 "Child change must not propagate to parent.";
489 parent_zoom_map->SetZoomLevelForHost(host, zoom_level_40);
490 ASSERT_EQ(
491 parent_zoom_map->GetZoomLevelForHostAndScheme("http", host),
492 zoom_level_40);
494 EXPECT_EQ(parent_zoom_map->GetZoomLevelForHostAndScheme("http", host),
495 child_zoom_map->GetZoomLevelForHostAndScheme("http", host)) <<
496 "Parent change should propagate to child.";
497 base::RunLoop().RunUntilIdle();
500 IN_PROC_BROWSER_TEST_F(HostZoomMapBrowserTest,
501 ParentDefaultZoomPropagatesToIncognitoChild) {
502 Profile* parent_profile = browser()->profile();
503 Profile* child_profile =
504 static_cast<ProfileImpl*>(parent_profile)->GetOffTheRecordProfile();
506 double new_default_zoom_level =
507 parent_profile->GetZoomLevelPrefs()->GetDefaultZoomLevelPref() + 1.f;
508 HostZoomMap* parent_host_zoom_map =
509 HostZoomMap::GetDefaultForBrowserContext(parent_profile);
510 HostZoomMap* child_host_zoom_map =
511 HostZoomMap::GetDefaultForBrowserContext(child_profile);
512 ASSERT_TRUE(parent_host_zoom_map);
513 ASSERT_TRUE(child_host_zoom_map);
514 EXPECT_NE(parent_host_zoom_map, child_host_zoom_map);
515 EXPECT_NE(new_default_zoom_level, child_host_zoom_map->GetDefaultZoomLevel());
517 parent_profile->GetZoomLevelPrefs()->SetDefaultZoomLevelPref(
518 new_default_zoom_level);
519 EXPECT_EQ(new_default_zoom_level, child_host_zoom_map->GetDefaultZoomLevel());