diff options
-rw-r--r-- | chrome/browser/automation/automation_provider.cc | 94 | ||||
-rw-r--r-- | chrome/browser/automation/automation_provider.h | 12 | ||||
-rw-r--r-- | chrome/test/functional/PYAUTO_TESTS | 1 | ||||
-rw-r--r-- | chrome/test/functional/prefs.py | 39 | ||||
-rw-r--r-- | chrome/test/pyautolib/prefs_info.py | 101 | ||||
-rw-r--r-- | chrome/test/pyautolib/pyauto.py | 46 | ||||
-rw-r--r-- | chrome/test/pyautolib/pyautolib.i | 14 |
7 files changed, 268 insertions, 39 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc index 7aec832..a878fca 100644 --- a/chrome/browser/automation/automation_provider.cc +++ b/chrome/browser/automation/automation_provider.cc @@ -1597,8 +1597,8 @@ void AutomationProvider::RemoveBookmark(int handle, *success = false; } -// Sample json input: { 'command': 'GetHistoryInfo', -// 'search_text': 'some text' } +// Sample json input: { "command": "GetHistoryInfo", +// "search_text": "some text" } // Refer chrome/test/pyautolib/history_info.py for sample json output. void AutomationProvider::GetHistoryInfo( DictionaryValue* args, @@ -1622,7 +1622,7 @@ void AutomationProvider::GetHistoryInfo( &AutomationProviderHistoryObserver::HistoryQueryComplete)); } -// Sample json input: { 'command': 'GetDownloadsInfo' } +// Sample json input: { "command": "GetDownloadsInfo" } // Refer chrome/test/pyautolib/download_info.py for sample json output. void AutomationProvider::GetDownloadsInfo( DictionaryValue* args, @@ -1634,7 +1634,7 @@ void AutomationProvider::GetDownloadsInfo( scoped_ptr<DictionaryValue> return_value(new DictionaryValue); if (!profile_->HasCreatedDownloadManager()) { - json_return = "{'error': 'no download manager'}"; + json_return = "{\"error\": \"no download manager\"}"; reply_return = false; } else { // Use DownloadManager's GetDownloads() method and not GetCurrentDownloads() @@ -1699,7 +1699,7 @@ void AutomationProvider::WaitForDownloadsToComplete( // Look for a quick return. if (!profile_->HasCreatedDownloadManager()) { - json_return = "{'error': 'no download manager'}"; + json_return = "{\"error\": \"no download manager\"}"; reply_return = false; } else { profile_->GetDownloadManager()->GetCurrentDownloads(&observer, @@ -1727,6 +1727,59 @@ void AutomationProvider::WaitForDownloadsToComplete( } } +// Sample json input: { "command": "GetPrefsInfo" } +// Refer chrome/test/pyautolib/prefs_info.py for sample json output. +void AutomationProvider::GetPrefsInfo(DictionaryValue* args, + IPC::Message* reply_message) { + std::string json_return; + bool reply_return = true; + + const PrefService::PreferenceSet& prefs = + profile_->GetPrefs()->preference_set(); + DictionaryValue* items = new DictionaryValue; + for (PrefService::PreferenceSet::const_iterator it = prefs.begin(); + it != prefs.end(); ++it) { + items->Set((*it)->name(), (*it)->GetValue()->DeepCopy()); + } + scoped_ptr<DictionaryValue> return_value(new DictionaryValue); + return_value->Set(L"prefs", items); // return_value owns items. + + base::JSONWriter::Write(return_value.get(), false, &json_return); + AutomationMsg_SendJSONRequest::WriteReplyParams( + reply_message, json_return, reply_return); + Send(reply_message); +} + +// Sample json input: { "command": "SetPrefs", "path": path, "value": value } +void AutomationProvider::SetPrefs(DictionaryValue* args, + IPC::Message* reply_message) { + bool reply_return = true; + std::string json_return = "{}"; + std::wstring path; + Value* val; + if (args->GetString(L"path", &path) && args->Get(L"value", &val)) { + PrefService* pref_service = profile_->GetPrefs(); + const PrefService::Preference* pref = + pref_service->FindPreference(path.c_str()); + if (!pref) { // Not a registered pref. + json_return = "{\"error\": \"pref not registered.\"}"; + reply_return = false; + } else if (pref->IsManaged()) { // Do not attempt to change a managed pref. + json_return = "{\"error\": \"pref is managed. cannot be changed.\"}"; + reply_return = false; + } else { // Set the pref. + pref_service->Set(path.c_str(), *val); + } + } else { + json_return = "{\"error\": \"no pref path or value given.\"}"; + reply_return = false; + } + + AutomationMsg_SendJSONRequest::WriteReplyParams( + reply_message, json_return, reply_return); + Send(reply_message); +} + void AutomationProvider::SendJSONRequest( int handle, std::string json_request, @@ -1765,27 +1818,30 @@ void AutomationProvider::SendJSONRequest( } } + // Map json commands to their handlers. + std::map<std::string, JsonHandler> handler_map; + handler_map["GetDownloadsInfo"] = &AutomationProvider::GetDownloadsInfo; + handler_map["GetHistoryInfo"] = &AutomationProvider::GetHistoryInfo; + handler_map["GetPrefsInfo"] = &AutomationProvider::GetPrefsInfo; + handler_map["SetPrefs"] = &AutomationProvider::SetPrefs; + handler_map["WaitForAllDownloadsToComplete"] = + &AutomationProvider::WaitForDownloadsToComplete; + if (error_string.empty()) { - // TODO(jrg): table of calls; async gets passed reply_message, - // sync methods gets passed an output json dict which we package - // up and send. Right now we only have one. - // TODO(nirnimesh): Replace if else cases with map. - if (command == "GetDownloadsInfo") { - this->GetDownloadsInfo(dict_value, reply_message); - return; - } else if (command == "GetHistoryInfo") { - this->GetHistoryInfo(dict_value, reply_message); - return; - } else if (command == "WaitForAllDownloadsToComplete") { - this->WaitForDownloadsToComplete(dict_value, reply_message); + if (handler_map.find(std::string(command)) != handler_map.end()) { + (this->*handler_map[command])(dict_value, reply_message); return; } else { - error_string = "unknown command"; + error_string = "Unknown command. Options: "; + for (std::map<std::string, JsonHandler>::const_iterator it = + handler_map.begin(); it != handler_map.end(); ++it) { + error_string += it->first + ", "; + } } } // If we hit an error, return info. - // Return a dict of {'error', 'descriptive_string_for_error'}. + // Return a dict of {"error", "descriptive_string_for_error"}. // Else return an empty dict. std::string json_string; bool success = true; diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h index d21456d..518eb8b 100644 --- a/chrome/browser/automation/automation_provider.h +++ b/chrome/browser/automation/automation_provider.h @@ -349,11 +349,23 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>, // Uses the JSON interface for input/output. void GetHistoryInfo(DictionaryValue* args, IPC::Message* reply_message); + // Get info about preferences. + // Uses the JSON interface for input/output. + void GetPrefsInfo(DictionaryValue* args, IPC::Message* reply_message); + + // Set prefs. + // Uses the JSON interface for input/output. + void SetPrefs(DictionaryValue* args, IPC::Message* reply_message); + // Generic pattern for pyautolib void SendJSONRequest(int handle, std::string json_request, IPC::Message* reply_message); + // Method ptr for json handlers. + typedef void (AutomationProvider::*JsonHandler)(DictionaryValue*, + IPC::Message*); + // Responds to InspectElement request void HandleInspectElementRequest(int handle, int x, diff --git a/chrome/test/functional/PYAUTO_TESTS b/chrome/test/functional/PYAUTO_TESTS index f037d48..a955243 100644 --- a/chrome/test/functional/PYAUTO_TESTS +++ b/chrome/test/functional/PYAUTO_TESTS @@ -23,6 +23,7 @@ 'history', 'test_basic.SimpleTest.testCanOpenGoogle', 'downloads', + 'prefs', 'special_tabs', ], diff --git a/chrome/test/functional/prefs.py b/chrome/test/functional/prefs.py index c02332b..31f8937 100644 --- a/chrome/test/functional/prefs.py +++ b/chrome/test/functional/prefs.py @@ -4,6 +4,7 @@ # found in the LICENSE file. import logging +import os import pyauto_functional # Must be imported before pyauto import pyauto @@ -13,24 +14,50 @@ class PrefsTest(pyauto.PyUITest): """TestCase for Preferences.""" def testSessionRestore(self): + """Test session restore preference.""" url1 = 'http://www.google.com/' url2 = 'http://news.google.com/' self.NavigateToURL(url1) self.AppendTab(pyauto.GURL(url2)) num_tabs = self.GetTabCount() # Set pref to restore session on startup - browser = self.GetBrowserWindow(0) - browser.SetIntPreference(pyauto.kRestoreOnStartup, 1) + self.SetPrefs(pyauto.kRestoreOnStartup, 1) logging.debug('Setting %s to 1' % pyauto.kRestoreOnStartup) - self.CloseBrowserAndServer() # Close browser - self.set_clear_profile(False) # Do not clear profile on next startup - self.LaunchBrowserAndServer() # Reopen browser + self.RestartBrowser(clear_profile=False) + # Verify + self.assertEqual(self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup), 1) self.assertEqual(num_tabs, self.GetTabCount()) self.ActivateTab(0) self.assertEqual(url1, self.GetActiveTabURL().spec()) self.ActivateTab(1) self.assertEqual(url2, self.GetActiveTabURL().spec()) - self.set_clear_profile(True) # Restore the flag to clear profile next + + def Debug(self): + """Test method for experimentation. + + This method will not run automatically. + """ + import pprint + pp = pprint.PrettyPrinter(indent=2) + while True: + raw_input('Interact with the browser and hit <enter> to dump prefs... ') + pp.pprint(self.GetPrefsInfo().Prefs()) + + def testSessionRestoreURLs(self): + """Verify restore URLs preference.""" + url1 = self.GetFileURLForPath(os.path.join(self.DataDir(), 'title1.html')) + url2 = self.GetFileURLForPath(os.path.join(self.DataDir(), 'title2.html')) + # Set pref to restore given URLs on startup + self.SetPrefs(pyauto.kRestoreOnStartup, 4) # 4 is for restoring URLs + self.SetPrefs(pyauto.kURLsToRestoreOnStartup, [url1, url2]) + self.RestartBrowser(clear_profile=False) + # Verify + self.assertEqual(self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup), 4) + self.assertEqual(2, self.GetTabCount()) + self.ActivateTab(0) + self.assertEqual(url1, self.GetActiveTabURL().spec()) + self.ActivateTab(1) + self.assertEqual(url2, self.GetActiveTabURL().spec()) if __name__ == '__main__': diff --git a/chrome/test/pyautolib/prefs_info.py b/chrome/test/pyautolib/prefs_info.py new file mode 100644 index 0000000..8b7204d --- /dev/null +++ b/chrome/test/pyautolib/prefs_info.py @@ -0,0 +1,101 @@ +#!/usr/bin/python + +# Copyright (c) 2010 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Python representation for Chromium Preferences. + +Obtain one of these from PyUITestSuite::GetPrefsInfo() call. + +Example: +class MyTest(pyauto.PyUITest): + def testBasic(self): + info = self.GetPrefsInfo() # fetch prefs snapshot + print info.Prefs() # all prefs + print info.Prefs('session.restore_on_startup') # a single pref + +See more tests in chrome/test/functional/prefs.py. +""" + +import simplejson as json + +from pyauto_errors import JSONInterfaceError + + +class PrefsInfo(object): + """Represent info for Chromium preferences. + + The info is represented as a hierarchy of prefs values. + The values could be plain (integer, bool, float) or complex (like + dictionary, list). + """ + def __init__(self, json_string): + """Initialize a PrefsInfo from a json string. + + Args: + json_string: a json string, as returned by a json ipc call for the + command 'GetPrefsInfo' + A typical string representing prefs snapshot looks like: + { u'prefs': + { u'alternate_error_pages': {u'enabled': True}, + u'autofill': { u'auxiliary_profiles_enabled': False, + u'default_creditcard': u'', + u'default_profile': u'', + u'enabled': True, + u'infobar_shown': False, + u'negative_upload_rate': 0.01, + u'positive_upload_rate': 0.01}, + u'bookmark_bar': {u'show_on_all_tabs': False}, + ... + ... + } + } + + Raises: + pyauto_errors.JSONInterfaceError if the automation call returns an error. + """ + # JSON string prepared in PrefsInfo() in automation_provider.cc + self.prefsdict = json.loads(json_string) + if self.prefsdict.has_key('error'): + raise JSONInterfaceError(self.prefsdict['error']) + + def Prefs(self, path=None): + """Get preferences. + + The preference dictionary (when using path=None) looks like: + + { u'alternate_error_pages': {u'enabled': True}, + u'autofill': { u'auxiliary_profiles_enabled': False, + u'default_creditcard': u'', + u'default_profile': u'', + u'enabled': True, + u'infobar_shown': False, + u'negative_upload_rate': 0.01, + u'positive_upload_rate': 0.01}, + u'bookmark_bar': {u'show_on_all_tabs': False}, + ... + ... + } + + In this case, to fetch the preference value for autofill enabled, use + 'autofill.enabled' as the path. + + Args: + path: If specified, return the preference item for the given path. + path is a dot-separated string like "session.restore_on_startup". + One of the equivalent names in chrome/common/pref_names.h could + also be used. + + Returns: + preference value. It could be a dictionary (like the example above), a + list or a plain value. + None, if prefernece for path not found (if path is given). + """ + all = self.prefsdict.get('prefs', {}) + if not path: # No path given. Return all prefs. + return all + for part in path.split('.'): # Narrow down to the requested prefs path. + all = all.get(part) + if all is None: return None + return all diff --git a/chrome/test/pyautolib/pyauto.py b/chrome/test/pyautolib/pyauto.py index 4575a73..b00f071 100644 --- a/chrome/test/pyautolib/pyauto.py +++ b/chrome/test/pyautolib/pyauto.py @@ -74,6 +74,8 @@ except ImportError: import bookmark_model import download_info import history_info +import prefs_info +from pyauto_errors import JSONInterfaceError import simplejson as json # found in third_party @@ -230,6 +232,50 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase): return download_info.DownloadInfo( self._SendJSONRequest(0, json.dumps({'command': 'GetDownloadsInfo'}))) + def GetPrefsInfo(self): + """Return info about preferences. + + This represents a snapshot of the preferences. If you expect preferences + to have changed, you need to call this method again to get a fresh + snapshot. + + Returns: + an instance of prefs_info.PrefsInfo + """ + return prefs_info.PrefsInfo( + self._SendJSONRequest(0, json.dumps({'command': 'GetPrefsInfo'}))) + + def SetPrefs(self, path, value): + """Set preference for the given path. + + Preferences are stored by Chromium as a hierarchical dictionary. + dot-separated paths can be used to refer to a particular preference. + example: "session.restore_on_startup" + + Some preferences are managed, that is, they cannot be changed by the + user. It's upto the user to know which ones can be changed. Typically, + the options available via Chromium preferences can be changed. + + Args: + path: the path the preference key that needs to be changed + example: "session.restore_on_startup" + One of the equivalent names in chrome/common/pref_names.h could + also be used. + value: the value to be set. It could be plain values like int, bool, + string or complex ones like list. + The user has to ensure that the right value is specified for the + right key. It's useful to dump the preferences first to determine + what type is expected for a particular preference path. + """ + cmd_dict = { + 'command': 'SetPrefs', + 'path': path, + 'value': value, + } + ret_dict = json.loads(self._SendJSONRequest(0, json.dumps(cmd_dict))) + if ret_dict.has_key('error'): + raise JSONInterfaceError(ret_dict['error']) + def WaitForAllDownloadsToComplete(self): """Wait for all downloads to complete.""" # Implementation detail: uses the generic "JSON command" model diff --git a/chrome/test/pyautolib/pyautolib.i b/chrome/test/pyautolib/pyautolib.i index 7156df6..1c36526 100644 --- a/chrome/test/pyautolib/pyautolib.i +++ b/chrome/test/pyautolib/pyautolib.i @@ -93,20 +93,6 @@ class BrowserProxy { %feature("docstring", "Get proxy to the tab at the given zero-based index") GetTab; scoped_refptr<TabProxy> GetTab(int tab_index) const; - - // Prefs - %feature("docstring", "Sets the int value of the specified preference. " - "Refer chrome/common/pref_names.h for the list of prefs.") - SetIntPreference; - bool SetIntPreference(const std::wstring& name, int value); - %feature("docstring", "Sets the string value of the specified preference. " - "Refer chrome/common/pref_names.h for the list of prefs.") - SetStringPreference; - bool SetStringPreference(const std::wstring& name, const std::wstring& value); - %feature("docstring", "Sets the boolean value of the specified preference. " - "Refer chrome/common/pref_names.h for the list of prefs.") - SetBooleanPreference; - bool SetBooleanPreference(const std::wstring& name, bool value); }; // TabProxy |