Bug 1142805 - Use ConfigParser to modify update-settings.ini
MozReview-Commit-ID: KbJofXTDa9p
--- a/testing/firefox-ui/harness/firefox_ui_harness/testcases.py
+++ b/testing/firefox-ui/harness/firefox_ui_harness/testcases.py
@@ -32,50 +32,42 @@ class UpdateTestCase(PuppeteerMixin, Mar
# http://mxr.mozilla.org/mozilla-central/source/toolkit/mozapps/update/nsUpdateService.js?rev=a9240b1eb2fb#4813
# http://mxr.mozilla.org/mozilla-central/source/toolkit/mozapps/update/nsUpdateService.js?rev=a9240b1eb2fb#4756
PREF_APP_UPDATE_ALTWINDOWTYPE = 'app.update.altwindowtype'
def __init__(self, *args, **kwargs):
super(UpdateTestCase, self).__init__(*args, **kwargs)
self.update_channel = kwargs.pop('update_channel')
+ self.update_mar_channels = set(kwargs.pop('update_mar_channels'))
self.update_url = kwargs.pop('update_url')
self.target_buildid = kwargs.pop('update_target_buildid')
self.target_version = kwargs.pop('update_target_version')
- self.update_mar_channels = set(kwargs.pop('update_mar_channels'))
- self.default_mar_channels = None
+ # Bug 604364 - Preparation to test multiple update steps
+ self.current_update_index = 0
+ self.download_duration = None
self.updates = []
def setUp(self, is_fallback=False):
super(UpdateTestCase, self).setUp()
self.software_update = SoftwareUpdate(self.marionette)
- self.download_duration = None
- # Bug 604364 - Preparation to test multiple update steps
- self.current_update_index = 0
+ # If requested modify the list of allowed MAR channels
+ if self.update_mar_channels:
+ self.software_update.mar_channels.add_channels(self.update_mar_channels)
# Ensure that there exists no already partially downloaded update
self.remove_downloaded_update()
self.set_preferences_defaults()
- # If requested modify the list of allowed MAR channels
- # Bug 1142805 - Modify file via Python directly
- if self.update_mar_channels:
- # Backup the original content and the path of the update-settings.ini file
- self.default_mar_channels = {
- 'content': self.software_update.mar_channels.config_file_contents,
- 'path': self.software_update.mar_channels.config_file_path,
- }
- self.software_update.mar_channels.add_channels(self.update_mar_channels)
-
# Bug 1142805 - Until we don't modify the channel-prefs.js and update-settings.ini
# files before Firefox gets started, a restart of Firefox is necessary to
# accept the new update channel.
self.restart()
# Dictionary which holds the information for each update
self.updates = [{
'build_pre': self.software_update.build_info,
@@ -106,18 +98,16 @@ class UpdateTestCase(PuppeteerMixin, Mar
output = pprint.pformat(self.updates)
self.logger.info('Update test results: \n{}'.format(output))
finally:
super(UpdateTestCase, self).tearDown()
# Ensure that no trace of an partially downloaded update remain
self.remove_downloaded_update()
- self.restore_config_files()
-
@property
def patch_info(self):
""" Returns information about the active update in the queue.
:returns: A dictionary with information about the active patch
"""
patch = self.software_update.patch_info
patch['download_duration'] = self.download_duration
@@ -360,28 +350,16 @@ class UpdateTestCase(PuppeteerMixin, Mar
def restart(self, *args, **kwargs):
super(UpdateTestCase, self).restart(*args, **kwargs)
# After a restart default preference values as set in the former session are lost.
# Make sure that any of those are getting restored.
self.set_preferences_defaults()
- def restore_config_files(self):
- # Reset update-settings.ini file if modified
- try:
- if self.default_mar_channels:
- path = self.default_mar_channels['path']
- self.logger.info('Restoring mar channel defaults for: {}'.format(path))
- with open(path, 'w') as f:
- f.write(self.default_mar_channels['content'])
- except IOError:
- self.logger.error('Failed to reset the default mar channels.',
- exc_info=True)
-
def set_preferences_defaults(self):
"""Set the default value for specific preferences to force its usage."""
if self.update_channel:
self.software_update.update_channel = self.update_channel
if self.update_url:
self.software_update.update_url = self.update_url
def wait_for_download_finished(self, window, timeout=TIMEOUT_UPDATE_DOWNLOAD):
--- a/testing/puppeteer/firefox/firefox_puppeteer/api/software_update.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/api/software_update.py
@@ -1,12 +1,13 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
+import ConfigParser
import os
import mozinfo
from firefox_puppeteer.base import BaseLib
from firefox_puppeteer.api.appinfo import AppInfo
from firefox_puppeteer.api.prefs import Preferences
@@ -76,88 +77,85 @@ class ActiveUpdate(BaseLib):
""")
class MARChannels(BaseLib):
"""Class to handle the allowed MAR channels as listed in update-settings.ini."""
INI_SECTION = 'Settings'
INI_OPTION = 'ACCEPTED_MAR_CHANNEL_IDS'
+ class MARConfigParser(ConfigParser.ConfigParser):
+ """INI parser which allows to read and write MAR config files.
+
+ Virtually identical to the original method, but delimit keys and values
+ with '=' instead of ' = '
+ """
+
+ def write(self, fp):
+ """Write an .ini-format representation of the configuration state."""
+ if self._defaults:
+ fp.write("[%s]\n" % ConfigParser.DEFAULTSECT)
+ for (key, value) in self._defaults.items():
+ fp.write("%s=%s\n" % (key, str(value).replace('\n', '\n\t')))
+ fp.write("\n")
+ for section in self._sections:
+ fp.write("[%s]\n" % section)
+ for (key, value) in self._sections[section].items():
+ if key == "__name__":
+ continue
+ if (value is not None) or (self._optcre == self.OPTCRE):
+ key = "=".join((key, str(value).replace('\n', '\n\t')))
+ fp.write("%s\n" % (key))
+ fp.write("\n")
+
def __init__(self, marionette):
BaseLib.__init__(self, marionette)
- self._ini_file_path = self.marionette.execute_script("""
+ self.config_file_path = self.marionette.execute_script("""
Components.utils.import('resource://gre/modules/Services.jsm');
let file = Services.dirsvc.get('GreD', Components.interfaces.nsIFile);
file.append('update-settings.ini');
return file.path;
""")
- @property
- def config_file_path(self):
- """The path to the update-settings.ini file."""
- return self._ini_file_path
-
- @property
- def config_file_contents(self):
- """The contents of the update-settings.ini file."""
- with open(self.config_file_path) as f:
- return f.read()
+ self.config = self.MARConfigParser()
+ self.config.optionxform = str
@property
def channels(self):
- """The channels as found in the ACCEPTED_MAR_CHANNEL_IDS option
- of the update-settings.ini file.
+ """The currently accepted MAR channels.
:returns: A set of channel names
"""
- channels = self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/FileUtils.jsm");
- let iniFactory = Components.classes['@mozilla.org/xpcom/ini-processor-factory;1']
- .getService(Components.interfaces.nsIINIParserFactory);
+ # Make sure to always read the current file contents
+ self.config.read(self.config_file_path)
- let file = new FileUtils.File(arguments[0]);
- let parser = iniFactory.createINIParser(file);
-
- return parser.getString(arguments[1], arguments[2]);
- """, script_args=[self.config_file_path, self.INI_SECTION, self.INI_OPTION])
- return set(channels.split(','))
+ return set(self.config.get(self.INI_SECTION, self.INI_OPTION).split(','))
@channels.setter
def channels(self, channels):
- """Set the channels in the update-settings.ini file.
+ """Set the accepted MAR channels.
:param channels: A set of channel names
"""
- new_channels = ','.join(channels)
- self.marionette.execute_script("""
- Components.utils.import("resource://gre/modules/FileUtils.jsm");
- let iniFactory = Components.classes['@mozilla.org/xpcom/ini-processor-factory;1']
- .getService(Components.interfaces.nsIINIParserFactory);
-
- let file = new FileUtils.File(arguments[0]);
-
- let writer = iniFactory.createINIParser(file)
- .QueryInterface(Components.interfaces.nsIINIParserWriter);
-
- writer.setString(arguments[1], arguments[2], arguments[3]);
- writer.writeFile(null, Components.interfaces.nsIINIParserWriter.WRITE_UTF16);
- """, script_args=[self.config_file_path, self.INI_SECTION, self.INI_OPTION, new_channels])
+ self.config.set(self.INI_SECTION, self.INI_OPTION, ','.join(channels))
+ with open(self.config_file_path, 'wb') as configfile:
+ self.config.write(configfile)
def add_channels(self, channels):
- """Add channels to the update-settings.ini file.
+ """Add additional MAR channels.
:param channels: A set of channel names to add
"""
self.channels = self.channels | set(channels)
def remove_channels(self, channels):
- """Remove channels from the update-settings.ini file.
+ """Remove MAR channels.
:param channels: A set of channel names to remove
"""
self.channels = self.channels - set(channels)
class SoftwareUpdate(BaseLib):
"""The SoftwareUpdate API adds support for an easy access to the update process."""