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