preferences_browsertest.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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.
4
5#include "chrome/browser/ui/webui/options/preferences_browsertest.h"
6
7#include <iostream>
8#include <sstream>
9
10#include "base/callback.h"
11#include "base/json/json_reader.h"
12#include "base/json/json_writer.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/prefs/pref_service.h"
15#include "base/stl_util.h"
16#include "base/values.h"
17#include "chrome/browser/chrome_notification_types.h"
18#include "chrome/browser/policy/browser_policy_connector.h"
19#include "chrome/browser/policy/external_data_fetcher.h"
20#include "chrome/browser/policy/policy_map.h"
21#include "chrome/browser/policy/policy_types.h"
22#include "chrome/browser/profiles/profile.h"
23#include "chrome/browser/ui/browser.h"
24#include "chrome/browser/ui/tabs/tab_strip_model.h"
25#include "chrome/common/pref_names.h"
26#include "chrome/common/url_constants.h"
27#include "chrome/test/base/ui_test_utils.h"
28#include "content/public/browser/notification_details.h"
29#include "content/public/browser/notification_source.h"
30#include "content/public/browser/render_view_host.h"
31#include "content/public/browser/web_contents.h"
32#include "content/public/test/browser_test_utils.h"
33#include "policy/policy_constants.h"
34#include "testing/gtest/include/gtest/gtest.h"
35#include "url/gurl.h"
36
37#if defined(OS_CHROMEOS)
38#include "base/strings/stringprintf.h"
39#include "chrome/browser/browser_process.h"
40#include "chrome/browser/chromeos/net/proxy_config_handler.h"
41#include "chrome/browser/chromeos/proxy_cros_settings_parser.h"
42#include "chrome/browser/chromeos/settings/cros_settings.h"
43#include "chrome/browser/prefs/proxy_config_dictionary.h"
44#include "chromeos/dbus/dbus_thread_manager.h"
45#include "chromeos/dbus/shill_profile_client.h"
46#include "chromeos/dbus/shill_service_client.h"
47#include "chromeos/network/favorite_state.h"
48#include "chromeos/network/network_state.h"
49#include "chromeos/network/network_state_handler.h"
50#include "chromeos/settings/cros_settings_names.h"
51#include "content/public/test/test_utils.h"
52#include "third_party/cros_system_api/dbus/service_constants.h"
53#endif
54
55using testing::AllOf;
56using testing::AnyNumber;
57using testing::Mock;
58using testing::Property;
59using testing::Return;
60using testing::_;
61
62namespace base {
63
64// Helper for using EXPECT_EQ() with base::Value.
65bool operator==(const Value& first, const Value& second) {
66  return first.Equals(&second);
67}
68
69// Helper for pretty-printing the contents of base::Value in case of failures.
70void PrintTo(const Value& value, std::ostream* stream) {
71  std::string json;
72  JSONWriter::Write(&value, &json);
73  *stream << json;
74}
75
76}  // namespace base
77
78// Googlemock matcher for base::Value.
79MATCHER_P(EqualsValue, expected, "") {
80  return arg && arg->Equals(expected);
81}
82
83PreferencesBrowserTest::PreferencesBrowserTest() {
84}
85
86PreferencesBrowserTest::~PreferencesBrowserTest() {
87}
88
89// Navigates to the settings page, causing the JavaScript pref handling code to
90// load and injects JavaScript testing code.
91void PreferencesBrowserTest::SetUpOnMainThread() {
92  ui_test_utils::NavigateToURL(browser(),
93                               GURL(chrome::kChromeUISettingsFrameURL));
94  SetUpPrefs();
95}
96
97void PreferencesBrowserTest::SetUpPrefs() {
98  content::WebContents* web_contents =
99      browser()->tab_strip_model()->GetActiveWebContents();
100  ASSERT_TRUE(web_contents);
101  render_view_host_ = web_contents->GetRenderViewHost();
102  ASSERT_TRUE(render_view_host_);
103  pref_service_ = browser()->profile()->GetPrefs();
104  pref_change_registrar_.Init(pref_service_);
105  ASSERT_TRUE(content::ExecuteScript(render_view_host_,
106      "function TestEnv() {"
107      "  this.sentinelName_ = 'download.prompt_for_download';"
108      "  this.prefs_ = [];"
109      "  TestEnv.instance_ = this;"
110      "}"
111      ""
112      "TestEnv.handleEvent = function(event) {"
113      "  var env = TestEnv.instance_;"
114      "  var name = event.type;"
115      "  env.removePrefListener_(name);"
116      "  if (name == TestEnv.sentinelName_)"
117      "    env.sentinelValue_ = event.value.value;"
118      "  else"
119      "    env.reply_[name] = event.value;"
120      "  if (env.fetching_ && !--env.fetching_ ||"
121      "      !env.fetching_ && name == env.sentinelName_) {"
122      "    env.removePrefListeners_();"
123      "    window.domAutomationController.send(JSON.stringify(env.reply_));"
124      "    delete env.reply_;"
125      "  }"
126      "};"
127      ""
128      "TestEnv.prototype = {"
129      "  addPrefListener_: function(name) {"
130      "    Preferences.getInstance().addEventListener(name,"
131      "                                               TestEnv.handleEvent);"
132      "  },"
133      ""
134      "  addPrefListeners_: function() {"
135      "    for (var i in this.prefs_)"
136      "      this.addPrefListener_(this.prefs_[i]);"
137      "  },"
138      ""
139      "  removePrefListener_: function(name) {"
140      "    Preferences.getInstance().removeEventListener(name,"
141      "                                                  TestEnv.handleEvent);"
142      "  },"
143      ""
144      "  removePrefListeners_: function() {"
145      "    for (var i in this.prefs_)"
146      "      this.removePrefListener_(this.prefs_[i]);"
147      "  },"
148      ""
149      ""
150      "  addPref: function(name) {"
151      "    this.prefs_.push(name);"
152      "  },"
153      ""
154      "  setupAndReply: function() {"
155      "    this.reply_ = {};"
156      "    Preferences.instance_ = new Preferences();"
157      "    this.addPref(this.sentinelName_);"
158      "    this.fetching_ = this.prefs_.length;"
159      "    this.addPrefListeners_();"
160      "    Preferences.getInstance().initialize();"
161      "  },"
162      ""
163      "  runAndReply: function(test) {"
164      "    this.reply_ = {};"
165      "    this.addPrefListeners_();"
166      "    test();"
167      "    this.sentinelValue_ = !this.sentinelValue_;"
168      "    Preferences.setBooleanPref(this.sentinelName_, this.sentinelValue_,"
169      "                               true);"
170      "  },"
171      ""
172      "  startObserving: function() {"
173      "    this.reply_ = {};"
174      "    this.addPrefListeners_();"
175      "  },"
176      ""
177      "  finishObservingAndReply: function() {"
178      "    this.sentinelValue_ = !this.sentinelValue_;"
179      "    Preferences.setBooleanPref(this.sentinelName_, this.sentinelValue_,"
180      "                               true);"
181      "  }"
182      "};"));
183}
184
185// Forwards notifications received when pref values change in the backend.
186void PreferencesBrowserTest::OnPreferenceChanged(const std::string& pref_name) {
187  OnCommit(pref_service_->FindPreference(pref_name.c_str()));
188}
189
190void PreferencesBrowserTest::SetUpInProcessBrowserTestFixture() {
191  // Sets up a mock policy provider for user and device policies.
192  EXPECT_CALL(policy_provider_, IsInitializationComplete(_))
193      .WillRepeatedly(Return(true));
194  EXPECT_CALL(policy_provider_, RegisterPolicyDomain(_))
195      .Times(AnyNumber());
196  policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
197      &policy_provider_);
198};
199
200void PreferencesBrowserTest::TearDownInProcessBrowserTestFixture() {
201  STLDeleteElements(&default_values_);
202  STLDeleteElements(&non_default_values_);
203}
204
205void PreferencesBrowserTest::SetUserPolicies(
206    const std::vector<std::string>& names,
207    const std::vector<base::Value*>& values,
208    policy::PolicyLevel level) {
209  policy::PolicyMap map;
210  for (size_t i = 0; i < names.size(); ++i) {
211    map.Set(names[i], level, policy::POLICY_SCOPE_USER,
212            values[i]->DeepCopy(), NULL);
213  }
214  policy_provider_.UpdateChromePolicy(map);
215}
216
217void PreferencesBrowserTest::ClearUserPolicies() {
218  policy::PolicyMap empty_policy_map;
219  policy_provider_.UpdateChromePolicy(empty_policy_map);
220}
221
222void PreferencesBrowserTest::SetUserValues(
223    const std::vector<std::string>& names,
224    const std::vector<base::Value*>& values) {
225  for (size_t i = 0; i < names.size(); ++i)
226    pref_service_->Set(names[i].c_str(), *values[i]);
227}
228
229void PreferencesBrowserTest::VerifyKeyValue(const base::DictionaryValue& dict,
230                                            const std::string& key,
231                                            const base::Value& expected) {
232  const base::Value* actual = NULL;
233  EXPECT_TRUE(dict.Get(key, &actual)) << "Was checking key: " << key;
234  if (actual)
235    EXPECT_EQ(expected, *actual) << "Was checking key: " << key;
236}
237
238void PreferencesBrowserTest::VerifyPref(const base::DictionaryValue* prefs,
239                                        const std::string& name,
240                                        const base::Value* value,
241                                        const std::string& controlledBy,
242                                        bool disabled,
243                                        bool uncommitted) {
244  const base::Value* pref = NULL;
245  const base::DictionaryValue* dict = NULL;
246  ASSERT_TRUE(prefs->GetWithoutPathExpansion(name, &pref));
247  ASSERT_TRUE(pref->GetAsDictionary(&dict));
248  VerifyKeyValue(*dict, "value", *value);
249  if (!controlledBy.empty())
250    VerifyKeyValue(*dict, "controlledBy", base::StringValue(controlledBy));
251  else
252    EXPECT_FALSE(dict->HasKey("controlledBy"));
253
254  if (disabled)
255    VerifyKeyValue(*dict, "disabled", base::FundamentalValue(true));
256  else if (dict->HasKey("disabled"))
257    VerifyKeyValue(*dict, "disabled", base::FundamentalValue(false));
258
259  if (uncommitted)
260    VerifyKeyValue(*dict, "uncommitted", base::FundamentalValue(true));
261  else if (dict->HasKey("uncommitted"))
262    VerifyKeyValue(*dict, "uncommitted", base::FundamentalValue(false));
263}
264
265void PreferencesBrowserTest::VerifyObservedPref(const std::string& json,
266                                                const std::string& name,
267                                                const base::Value* value,
268                                                const std::string& controlledBy,
269                                                bool disabled,
270                                                bool uncommitted) {
271  scoped_ptr<base::Value> observed_value_ptr(base::JSONReader::Read(json));
272  const base::DictionaryValue* observed_dict;
273  ASSERT_TRUE(observed_value_ptr.get());
274  ASSERT_TRUE(observed_value_ptr->GetAsDictionary(&observed_dict));
275  VerifyPref(observed_dict, name, value, controlledBy, disabled, uncommitted);
276}
277
278void PreferencesBrowserTest::VerifyObservedPrefs(
279    const std::string& json,
280    const std::vector<std::string>& names,
281    const std::vector<base::Value*>& values,
282    const std::string& controlledBy,
283    bool disabled,
284    bool uncommitted) {
285  scoped_ptr<base::Value> observed_value_ptr(base::JSONReader::Read(json));
286  const base::DictionaryValue* observed_dict;
287  ASSERT_TRUE(observed_value_ptr.get());
288  ASSERT_TRUE(observed_value_ptr->GetAsDictionary(&observed_dict));
289  for (size_t i = 0; i < names.size(); ++i)
290    VerifyPref(observed_dict, names[i], values[i], controlledBy, disabled,
291               uncommitted);
292}
293
294void PreferencesBrowserTest::ExpectNoCommit(const std::string& name) {
295  pref_change_registrar_.Add(
296      name.c_str(),
297      base::Bind(&PreferencesBrowserTest::OnPreferenceChanged,
298                 base::Unretained(this)));
299  EXPECT_CALL(*this, OnCommit(Property(&PrefService::Preference::name, name)))
300      .Times(0);
301}
302
303void PreferencesBrowserTest::ExpectSetCommit(const std::string& name,
304                                             const base::Value* value) {
305  pref_change_registrar_.Add(
306      name.c_str(),
307      base::Bind(&PreferencesBrowserTest::OnPreferenceChanged,
308                 base::Unretained(this)));
309  EXPECT_CALL(*this, OnCommit(AllOf(
310      Property(&PrefService::Preference::name, name),
311      Property(&PrefService::Preference::IsUserControlled, true),
312      Property(&PrefService::Preference::GetValue, EqualsValue(value)))));
313}
314
315void PreferencesBrowserTest::ExpectClearCommit(const std::string& name) {
316  pref_change_registrar_.Add(
317      name.c_str(),
318      base::Bind(&PreferencesBrowserTest::OnPreferenceChanged,
319                 base::Unretained(this)));
320  EXPECT_CALL(*this, OnCommit(AllOf(
321      Property(&PrefService::Preference::name, name),
322      Property(&PrefService::Preference::IsUserControlled, false))));
323}
324
325void PreferencesBrowserTest::VerifyAndClearExpectations() {
326  Mock::VerifyAndClearExpectations(this);
327  pref_change_registrar_.RemoveAll();
328}
329
330void PreferencesBrowserTest::SetupJavaScriptTestEnvironment(
331    const std::vector<std::string>& pref_names,
332    std::string* observed_json) const {
333  std::stringstream javascript;
334  javascript << "var testEnv = new TestEnv();";
335  for (std::vector<std::string>::const_iterator name = pref_names.begin();
336       name != pref_names.end(); ++name)
337    javascript << "testEnv.addPref('" << name->c_str() << "');";
338  javascript << "testEnv.setupAndReply();";
339  std::string temp_observed_json;
340  if (!observed_json)
341    observed_json = &temp_observed_json;
342  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
343      render_view_host_, javascript.str(), observed_json));
344}
345
346void PreferencesBrowserTest::SetPref(const std::string& name,
347                                     const std::string& type,
348                                     const base::Value* value,
349                                     bool commit,
350                                     std::string* observed_json) {
351  scoped_ptr<base::Value> commit_ptr(new base::FundamentalValue(commit));
352  std::stringstream javascript;
353  javascript << "testEnv.runAndReply(function() {"
354             << "  Preferences.set" << type << "Pref("
355             << "      '" << name << "',"
356             << "      " << *value << ","
357             << "      " << *commit_ptr << ");"
358             << "});";
359  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
360      render_view_host_, javascript.str(), observed_json));
361}
362
363void PreferencesBrowserTest::VerifySetPref(const std::string& name,
364                                           const std::string& type,
365                                           const base::Value* value,
366                                           bool commit) {
367  if (commit)
368    ExpectSetCommit(name, value);
369  else
370    ExpectNoCommit(name);
371  std::string observed_json;
372  SetPref(name, type, value, commit, &observed_json);
373  VerifyObservedPref(observed_json, name, value, std::string(), false, !commit);
374  VerifyAndClearExpectations();
375}
376
377void PreferencesBrowserTest::VerifyClearPref(const std::string& name,
378                                             const base::Value* value,
379                                             bool commit) {
380  if (commit)
381    ExpectClearCommit(name);
382  else
383    ExpectNoCommit(name);
384  scoped_ptr<base::Value> commit_ptr(new base::FundamentalValue(commit));
385  std::string commit_json;
386  base::JSONWriter::Write(commit_ptr.get(), &commit_json);
387  std::stringstream javascript;
388  javascript << "testEnv.runAndReply(function() {"
389             << "    Preferences.clearPref("
390             << "      '" << name.c_str() << "',"
391             << "      " << commit_json.c_str() << ");});";
392  std::string observed_json;
393  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
394      render_view_host_, javascript.str(), &observed_json));
395  VerifyObservedPref(observed_json, name, value, "recommended", false, !commit);
396  VerifyAndClearExpectations();
397}
398
399void PreferencesBrowserTest::VerifyCommit(const std::string& name,
400                                          const base::Value* value,
401                                          const std::string& controlledBy) {
402  std::stringstream javascript;
403  javascript << "testEnv.runAndReply(function() {"
404             << "    Preferences.getInstance().commitPref("
405             << "        '" << name.c_str() << "');});";
406  std::string observed_json;
407  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
408      render_view_host_, javascript.str(), &observed_json));
409  VerifyObservedPref(observed_json, name, value, controlledBy, false, false);
410}
411
412void PreferencesBrowserTest::VerifySetCommit(const std::string& name,
413                                             const base::Value* value) {
414  ExpectSetCommit(name, value);
415  VerifyCommit(name, value, std::string());
416  VerifyAndClearExpectations();
417}
418
419void PreferencesBrowserTest::VerifyClearCommit(const std::string& name,
420                                               const base::Value* value) {
421  ExpectClearCommit(name);
422  VerifyCommit(name, value, "recommended");
423  VerifyAndClearExpectations();
424}
425
426void PreferencesBrowserTest::VerifyRollback(const std::string& name,
427                                            const base::Value* value,
428                                            const std::string& controlledBy) {
429  ExpectNoCommit(name);
430  std::stringstream javascript;
431  javascript << "testEnv.runAndReply(function() {"
432             << "    Preferences.getInstance().rollbackPref("
433             << "        '" << name.c_str() << "');});";
434  std::string observed_json;
435  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
436      render_view_host_, javascript.str(), &observed_json));
437  VerifyObservedPref(observed_json, name, value, controlledBy, false, true);
438  VerifyAndClearExpectations();
439}
440
441void PreferencesBrowserTest::StartObserving() {
442  ASSERT_TRUE(content::ExecuteScript(
443      render_view_host_, "testEnv.startObserving();"));
444}
445
446void PreferencesBrowserTest::FinishObserving(std::string* observed_json) {
447  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
448      render_view_host_,
449      "testEnv.finishObservingAndReply();",
450      observed_json));
451}
452
453void PreferencesBrowserTest::UseDefaultTestPrefs(bool includeListPref) {
454  // Boolean pref.
455  types_.push_back("Boolean");
456  pref_names_.push_back(prefs::kAlternateErrorPagesEnabled);
457  policy_names_.push_back(policy::key::kAlternateErrorPagesEnabled);
458  non_default_values_.push_back(new base::FundamentalValue(false));
459
460  // Integer pref.
461  types_.push_back("Integer");
462  pref_names_.push_back(prefs::kRestoreOnStartup);
463  policy_names_.push_back(policy::key::kRestoreOnStartup);
464  non_default_values_.push_back(new base::FundamentalValue(4));
465
466  // List pref.
467  if (includeListPref) {
468    types_.push_back("List");
469    pref_names_.push_back(prefs::kURLsToRestoreOnStartup);
470    policy_names_.push_back(policy::key::kRestoreOnStartupURLs);
471    base::ListValue* list = new base::ListValue;
472    list->Append(new base::StringValue("http://www.google.com"));
473    list->Append(new base::StringValue("http://example.com"));
474    non_default_values_.push_back(list);
475  }
476
477  // Retrieve default values.
478  for (std::vector<std::string>::const_iterator name = pref_names_.begin();
479        name != pref_names_.end(); ++name) {
480    default_values_.push_back(
481        pref_service_->GetDefaultPrefValue(name->c_str())->DeepCopy());
482  }
483}
484
485// Verifies that initializing the JavaScript Preferences class fires the correct
486// notifications in JavaScript.
487IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, FetchPrefs) {
488  UseDefaultTestPrefs(true);
489  std::string observed_json;
490
491  // Verify notifications when default values are in effect.
492  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
493  VerifyObservedPrefs(
494      observed_json, pref_names_, default_values_, std::string(), false, false);
495
496  // Verify notifications when recommended values are in effect.
497  SetUserPolicies(policy_names_, non_default_values_,
498                  policy::POLICY_LEVEL_RECOMMENDED);
499  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
500  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_,
501                      "recommended", false, false);
502
503  // Verify notifications when mandatory values are in effect.
504  SetUserPolicies(policy_names_, non_default_values_,
505                  policy::POLICY_LEVEL_MANDATORY);
506  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
507  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_,
508                      "policy", true, false);
509
510  // Verify notifications when user-modified values are in effect.
511  ClearUserPolicies();
512  SetUserValues(pref_names_, non_default_values_);
513  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
514  VerifyObservedPrefs(observed_json,
515                      pref_names_,
516                      non_default_values_,
517                      std::string(),
518                      false,
519                      false);
520}
521
522// Verifies that setting a user-modified pref value through the JavaScript
523// Preferences class fires the correct notification in JavaScript and causes the
524// change to be committed to the C++ backend.
525IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, SetPrefs) {
526  UseDefaultTestPrefs(false);
527
528  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
529  for (size_t i = 0; i < pref_names_.size(); ++i)
530    VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], true);
531}
532
533// Verifies that clearing a user-modified pref value through the JavaScript
534// Preferences class fires the correct notification in JavaScript and causes the
535// change to be committed to the C++ backend.
536IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, ClearPrefs) {
537  UseDefaultTestPrefs(false);
538
539  SetUserPolicies(policy_names_, default_values_,
540                  policy::POLICY_LEVEL_RECOMMENDED);
541  SetUserValues(pref_names_, non_default_values_);
542  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
543  for (size_t i = 0; i < pref_names_.size(); ++i)
544    VerifyClearPref(pref_names_[i], default_values_[i], true);
545}
546
547// Verifies that when the user-modified value of a dialog pref is set and the
548// change then committed through the JavaScript Preferences class, the correct
549// notifications fire and a commit to the C++ backend occurs in the latter step
550// only.
551IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsSetCommit) {
552  UseDefaultTestPrefs(false);
553
554  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
555  for (size_t i = 0; i < pref_names_.size(); ++i) {
556    VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], false);
557    VerifySetCommit(pref_names_[i], non_default_values_[i]);
558  }
559}
560
561// Verifies that when the user-modified value of a dialog pref is set and the
562// change then rolled back through the JavaScript Preferences class, the correct
563// notifications fire and no commit to the C++ backend occurs.
564IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsSetRollback) {
565  UseDefaultTestPrefs(false);
566
567  // Verify behavior when default values are in effect.
568  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
569  for (size_t i = 0; i < pref_names_.size(); ++i) {
570    VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], false);
571    VerifyRollback(pref_names_[i], default_values_[i], std::string());
572  }
573
574  // Verify behavior when recommended values are in effect.
575  SetUserPolicies(policy_names_, default_values_,
576                  policy::POLICY_LEVEL_RECOMMENDED);
577  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
578  for (size_t i = 0; i < pref_names_.size(); ++i) {
579    VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], false);
580    VerifyRollback(pref_names_[i], default_values_[i], "recommended");
581  }
582}
583
584// Verifies that when the user-modified value of a dialog pref is cleared and
585// the change then committed through the JavaScript Preferences class, the
586// correct notifications fire and a commit to the C++ backend occurs in the
587// latter step only.
588IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsClearCommit) {
589  UseDefaultTestPrefs(false);
590
591  SetUserPolicies(policy_names_, default_values_,
592                  policy::POLICY_LEVEL_RECOMMENDED);
593  SetUserValues(pref_names_, non_default_values_);
594  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
595  for (size_t i = 0; i < pref_names_.size(); ++i) {
596    VerifyClearPref(pref_names_[i], default_values_[i], false);
597    VerifyClearCommit(pref_names_[i], default_values_[i]);
598  }
599}
600
601// Verifies that when the user-modified value of a dialog pref is cleared and
602// the change then rolled back through the JavaScript Preferences class, the
603// correct notifications fire and no commit to the C++ backend occurs.
604IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsClearRollback) {
605  UseDefaultTestPrefs(false);
606
607  SetUserPolicies(policy_names_, default_values_,
608                  policy::POLICY_LEVEL_RECOMMENDED);
609  SetUserValues(pref_names_, non_default_values_);
610  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
611  for (size_t i = 0; i < pref_names_.size(); ++i) {
612    VerifyClearPref(pref_names_[i], default_values_[i], false);
613    VerifyRollback(pref_names_[i], non_default_values_[i], std::string());
614  }
615}
616
617// Verifies that when preference values change in the C++ backend, the correct
618// notifications fire in JavaScript.
619IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, NotificationsOnBackendChanges) {
620  UseDefaultTestPrefs(false);
621  std::string observed_json;
622
623  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
624
625  // Verify notifications when recommended values come into effect.
626  StartObserving();
627  SetUserPolicies(policy_names_, non_default_values_,
628                  policy::POLICY_LEVEL_RECOMMENDED);
629  FinishObserving(&observed_json);
630  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_,
631                      "recommended", false, false);
632
633  // Verify notifications when mandatory values come into effect.
634  StartObserving();
635  SetUserPolicies(policy_names_, non_default_values_,
636                  policy::POLICY_LEVEL_MANDATORY);
637  FinishObserving(&observed_json);
638  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_,
639                      "policy", true, false);
640
641  // Verify notifications when default values come into effect.
642  StartObserving();
643  ClearUserPolicies();
644  FinishObserving(&observed_json);
645  VerifyObservedPrefs(
646      observed_json, pref_names_, default_values_, std::string(), false, false);
647
648  // Verify notifications when user-modified values come into effect.
649  StartObserving();
650  SetUserValues(pref_names_, non_default_values_);
651  FinishObserving(&observed_json);
652  VerifyObservedPrefs(observed_json,
653                      pref_names_,
654                      non_default_values_,
655                      std::string(),
656                      false,
657                      false);
658}
659
660#if defined(OS_CHROMEOS)
661
662// Verifies that initializing the JavaScript Preferences class fires the correct
663// notifications in JavaScript for pref values handled by the
664// CoreChromeOSOptionsHandler class.
665IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, ChromeOSDeviceFetchPrefs) {
666  std::vector<base::Value*> decorated_non_default_values;
667  std::string observed_json;
668
669  // Boolean pref.
670  pref_names_.push_back(chromeos::kAccountsPrefAllowGuest);
671  default_values_.push_back(new base::FundamentalValue(true));
672  non_default_values_.push_back(new base::FundamentalValue(false));
673  decorated_non_default_values.push_back(
674      non_default_values_.back()->DeepCopy());
675
676  // String pref.
677  pref_names_.push_back(chromeos::kReleaseChannel);
678  default_values_.push_back(new base::StringValue(""));
679  non_default_values_.push_back(new base::StringValue("stable-channel"));
680  decorated_non_default_values.push_back(
681      non_default_values_.back()->DeepCopy());
682
683  // List pref.
684  pref_names_.push_back(chromeos::kAccountsPrefUsers);
685  default_values_.push_back(new base::ListValue);
686  base::ListValue* list = new base::ListValue;
687  list->Append(new base::StringValue("me@google.com"));
688  list->Append(new base::StringValue("you@google.com"));
689  non_default_values_.push_back(list);
690  list = new base::ListValue;
691  base::DictionaryValue* dict = new base::DictionaryValue;
692  dict->SetString("username", "me@google.com");
693  dict->SetString("name", "me@google.com");
694  dict->SetString("email", "");
695  dict->SetBoolean("owner", false);
696  list->Append(dict);
697  dict = new base::DictionaryValue;
698  dict->SetString("username", "you@google.com");
699  dict->SetString("name", "you@google.com");
700  dict->SetString("email", "");
701  dict->SetBoolean("owner", false);
702  list->Append(dict);
703  decorated_non_default_values.push_back(list);
704
705  // Verify notifications when default values are in effect.
706  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
707  VerifyObservedPrefs(observed_json, pref_names_, default_values_,
708                      "owner", true, false);
709
710  // Verify notifications when mandatory values are in effect.
711  chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get();
712  for (size_t i = 0; i < pref_names_.size(); ++i)
713    cros_settings->Set(pref_names_[i], *non_default_values_[i]);
714  // FIXME(bartfab): Find a way to simulate enterprise enrollment in browser
715  // tests. Only if Chrome thinks that it is enrolled will the device prefs be
716  // decorated with "controlledBy: policy".
717  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
718  VerifyObservedPrefs(observed_json, pref_names_, decorated_non_default_values,
719                      "owner", true, false);
720
721  STLDeleteElements(&decorated_non_default_values);
722}
723
724namespace {
725
726const char* kUserProfilePath = "user_profile";
727
728}  // namespace
729
730class ProxyPreferencesBrowserTest : public PreferencesBrowserTest {
731 public:
732  virtual void SetUpOnMainThread() OVERRIDE {
733    SetupNetworkEnvironment();
734    content::RunAllPendingInMessageLoop();
735
736    scoped_ptr<base::DictionaryValue> proxy_config_dict(
737        ProxyConfigDictionary::CreateFixedServers("127.0.0.1:8080",
738                                                  "*.google.com, 1.2.3.4:22"));
739
740    ProxyConfigDictionary proxy_config(proxy_config_dict.get());
741
742    const chromeos::FavoriteState* network = GetDefaultFavoriteNetwork();
743    ASSERT_TRUE(network);
744    chromeos::proxy_config::SetProxyConfigForFavoriteNetwork(proxy_config,
745                                                             *network);
746
747    std::string url = base::StringPrintf("%s?network=%s",
748                                         chrome::kChromeUIProxySettingsURL,
749                                         network->path().c_str());
750
751    ui_test_utils::NavigateToURL(browser(), GURL(url));
752    SetUpPrefs();
753  }
754
755 protected:
756  void SetupNetworkEnvironment() {
757    chromeos::ShillProfileClient::TestInterface* profile_test =
758        chromeos::DBusThreadManager::Get()->GetShillProfileClient()
759            ->GetTestInterface();
760    chromeos::ShillServiceClient::TestInterface* service_test =
761        chromeos::DBusThreadManager::Get()->GetShillServiceClient()
762            ->GetTestInterface();
763
764    profile_test->AddProfile(kUserProfilePath, "user");
765
766    service_test->ClearServices();
767    service_test->AddService("stub_ethernet",
768                             "eth0",
769                             shill::kTypeEthernet,
770                             shill::kStateOnline,
771                             true,   // add to visible
772                             true);  // add to watchlist
773    service_test->SetServiceProperty("stub_ethernet",
774                                     shill::kGuidProperty,
775                                     base::StringValue("stub_ethernet"));
776    service_test->SetServiceProperty("stub_ethernet",
777                                     shill::kProfileProperty,
778                                     base::StringValue(kUserProfilePath));
779    profile_test->AddService(kUserProfilePath, "stub_wifi2");
780  }
781
782  void SetONCPolicy(const char* policy_name, policy::PolicyScope scope) {
783    std::string onc_policy =
784        "{ \"NetworkConfigurations\": ["
785        "    { \"GUID\": \"stub_ethernet\","
786        "      \"Type\": \"Ethernet\","
787        "      \"Name\": \"My Ethernet\","
788        "      \"Ethernet\": {"
789        "        \"Authentication\": \"None\" },"
790        "      \"ProxySettings\": {"
791        "        \"PAC\": \"http://domain.com/x\","
792        "        \"Type\": \"PAC\" }"
793        "    }"
794        "  ],"
795        "  \"Type\": \"UnencryptedConfiguration\""
796        "}";
797
798    policy::PolicyMap map;
799    map.Set(policy_name,
800            policy::POLICY_LEVEL_MANDATORY,
801            scope,
802            new base::StringValue(onc_policy),
803            NULL);
804    policy_provider_.UpdateChromePolicy(map);
805
806    content::RunAllPendingInMessageLoop();
807  }
808
809  const chromeos::FavoriteState* GetDefaultFavoriteNetwork() {
810    chromeos::NetworkStateHandler* handler =
811        chromeos::NetworkHandler::Get()->network_state_handler();
812    return handler->DefaultFavoriteNetwork();
813  }
814
815  void SetProxyPref(const std::string& name, const base::Value& value) {
816    std::string type;
817    switch (value.GetType()) {
818      case base::Value::TYPE_BOOLEAN:
819        type = "Boolean";
820        break;
821      case base::Value::TYPE_INTEGER:
822        type = "Integer";
823        break;
824      case base::Value::TYPE_STRING:
825        type = "String";
826        break;
827      default:
828        ASSERT_TRUE(false);
829    }
830
831    std::string observed_json;
832    SetPref(name, type, &value, true, &observed_json);
833  }
834
835  void VerifyCurrentProxyServer(const std::string& expected_server,
836                                onc::ONCSource expected_source) {
837    const chromeos::FavoriteState* network = GetDefaultFavoriteNetwork();
838    ASSERT_TRUE(network);
839    onc::ONCSource actual_source;
840    scoped_ptr<ProxyConfigDictionary> proxy_dict =
841        chromeos::proxy_config::GetProxyConfigForFavoriteNetwork(
842            pref_service_,
843            g_browser_process->local_state(),
844            *network,
845            &actual_source);
846    ASSERT_TRUE(proxy_dict);
847    std::string actual_proxy_server;
848    EXPECT_TRUE(proxy_dict->GetProxyServer(&actual_proxy_server));
849    EXPECT_EQ(expected_server, actual_proxy_server);
850    EXPECT_EQ(expected_source, actual_source);
851  }
852};
853
854// Verifies that proxy settings are correctly pushed to JavaScript during
855// initialization of the proxy settings page.
856IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSInitializeProxy) {
857  // Boolean pref.
858  pref_names_.push_back(chromeos::kProxySingle);
859  non_default_values_.push_back(new base::FundamentalValue(true));
860
861  // Integer prefs.
862  pref_names_.push_back(chromeos::kProxySingleHttpPort);
863  non_default_values_.push_back(new base::FundamentalValue(8080));
864
865  // String pref.
866  pref_names_.push_back(chromeos::kProxySingleHttp);
867  non_default_values_.push_back(new base::StringValue("127.0.0.1"));
868
869  // List pref.
870  pref_names_.push_back(chromeos::kProxyIgnoreList);
871  base::ListValue* list = new base::ListValue();
872  list->Append(new base::StringValue("*.google.com"));
873  list->Append(new base::StringValue("1.2.3.4:22"));
874  non_default_values_.push_back(list);
875
876  // Verify that no policy is presented to the UI. This must be verified on the
877  // kProxyType and the kUseSharedProxies prefs.
878  pref_names_.push_back(chromeos::kProxyType);
879  non_default_values_.push_back(new base::FundamentalValue(2));
880
881  pref_names_.push_back(prefs::kUseSharedProxies);
882  non_default_values_.push_back(new base::FundamentalValue(false));
883
884  std::string observed_json;
885  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
886  VerifyObservedPrefs(
887      observed_json, pref_names_, non_default_values_, "", false, false);
888}
889
890IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ONCPolicy) {
891  SetONCPolicy(policy::key::kOpenNetworkConfiguration,
892               policy::POLICY_SCOPE_USER);
893
894  // Verify that per-network policy is presented to the UI. This must be
895  // verified on the kProxyType.
896  pref_names_.push_back(chromeos::kProxyType);
897  non_default_values_.push_back(new base::FundamentalValue(3));
898
899  std::string observed_json;
900  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
901  VerifyObservedPrefs(
902      observed_json, pref_names_, non_default_values_, "policy", true, false);
903
904  // Verify that 'use-shared-proxies' is not affected by per-network policy.
905  pref_names_.clear();
906  STLDeleteElements(&non_default_values_);
907  pref_names_.push_back(prefs::kUseSharedProxies);
908  non_default_values_.push_back(new base::FundamentalValue(false));
909
910  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
911  VerifyObservedPrefs(
912      observed_json, pref_names_, non_default_values_, "", false, false);
913}
914
915IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, DeviceONCPolicy) {
916  SetONCPolicy(policy::key::kDeviceOpenNetworkConfiguration,
917               policy::POLICY_SCOPE_MACHINE);
918
919  // Verify that the policy is presented to the UI. This verification must be
920  // done on the kProxyType pref.
921  pref_names_.push_back(chromeos::kProxyType);
922  non_default_values_.push_back(new base::FundamentalValue(3));
923
924  std::string observed_json;
925  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
926  VerifyObservedPrefs(
927      observed_json, pref_names_, non_default_values_, "policy", true, false);
928
929  // Verify that 'use-shared-proxies' is not affected by per-network policy.
930  pref_names_.clear();
931  STLDeleteElements(&non_default_values_);
932  pref_names_.push_back(prefs::kUseSharedProxies);
933  non_default_values_.push_back(new base::FundamentalValue(false));
934
935  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
936  VerifyObservedPrefs(
937      observed_json, pref_names_, non_default_values_, "", false, false);
938}
939
940IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, UserProxyPolicy) {
941  policy_names_.push_back(policy::key::kProxyMode);
942  default_values_.push_back(
943      new base::StringValue(ProxyPrefs::kAutoDetectProxyModeName));
944  SetUserPolicies(
945      policy_names_, default_values_, policy::POLICY_LEVEL_MANDATORY);
946  content::RunAllPendingInMessageLoop();
947
948  // Verify that the policy is presented to the UI. This verification must be
949  // done on the kProxyType pref.
950  pref_names_.push_back(chromeos::kProxyType);
951  non_default_values_.push_back(new base::FundamentalValue(3));
952
953  // Verify that 'use-shared-proxies' is controlled by the policy.
954  pref_names_.push_back(prefs::kUseSharedProxies);
955  non_default_values_.push_back(new base::FundamentalValue(false));
956
957  std::string observed_json;
958  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
959  VerifyObservedPrefs(
960      observed_json, pref_names_, non_default_values_, "policy", true, false);
961}
962
963// Verifies that modifications to the proxy settings are correctly pushed from
964// JavaScript to the ProxyConfig property stored in the network configuration.
965IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSSetProxy) {
966  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
967
968  SetProxyPref(chromeos::kProxySingleHttpPort, base::FundamentalValue(123));
969  SetProxyPref(chromeos::kProxySingleHttp, base::StringValue("www.adomain.xy"));
970
971  VerifyCurrentProxyServer("www.adomain.xy:123",
972                           onc::ONC_SOURCE_NONE);
973}
974
975// Verify that default proxy ports are used and that ports can be updated
976// without affecting the previously set hosts.
977IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSProxyDefaultPorts) {
978  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
979
980  // Set to manual, per scheme proxy.
981  SetProxyPref(chromeos::kProxySingle, base::FundamentalValue(false));
982
983  // Set hosts but no ports.
984  SetProxyPref(chromeos::kProxyHttpUrl, base::StringValue("a.com"));
985  SetProxyPref(chromeos::kProxyHttpsUrl, base::StringValue("4.3.2.1"));
986  SetProxyPref(chromeos::kProxyFtpUrl, base::StringValue("c.com"));
987  SetProxyPref(chromeos::kProxySocks, base::StringValue("d.com"));
988
989  // Verify default ports.
990  VerifyCurrentProxyServer(
991      "http=a.com:80;https=4.3.2.1:80;ftp=c.com:80;socks=socks4://d.com:1080",
992      onc::ONC_SOURCE_NONE);
993
994  // Set and verify the ports.
995  SetProxyPref(chromeos::kProxyHttpPort, base::FundamentalValue(1));
996  SetProxyPref(chromeos::kProxyHttpsPort, base::FundamentalValue(2));
997  SetProxyPref(chromeos::kProxyFtpPort, base::FundamentalValue(3));
998  SetProxyPref(chromeos::kProxySocksPort, base::FundamentalValue(4));
999
1000  VerifyCurrentProxyServer(
1001      "http=a.com:1;https=4.3.2.1:2;ftp=c.com:3;socks=socks4://d.com:4",
1002      onc::ONC_SOURCE_NONE);
1003}
1004
1005#endif
1006