Bug 1142805 - Set update channel via default branch.
MozReview-Commit-ID: 5iHnNhLRCK4
--- a/testing/firefox-ui/harness/firefox_ui_harness/testcases.py
+++ b/testing/firefox-ui/harness/firefox_ui_harness/testcases.py
@@ -31,24 +31,22 @@ class UpdateTestCase(PuppeteerMixin, Mar
# raised. See:
# 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_url = kwargs.pop('update_url')
self.target_buildid = kwargs.pop('update_target_buildid')
self.target_version = kwargs.pop('update_target_version')
- self.update_channel = kwargs.pop('update_channel')
- self.default_update_channel = None
-
self.update_mar_channels = set(kwargs.pop('update_mar_channels'))
self.default_mar_channels = None
self.updates = []
def setUp(self, is_fallback=False):
super(UpdateTestCase, self).setUp()
@@ -58,27 +56,16 @@ class UpdateTestCase(PuppeteerMixin, Mar
# Bug 604364 - Preparation to test multiple update steps
self.current_update_index = 0
# Ensure that there exists no already partially downloaded update
self.remove_downloaded_update()
self.set_preferences_defaults()
- # If requested modify the default update channel. It will be active
- # after the next restart of the application
- # Bug 1142805 - Modify file via Python directly
- if self.update_channel:
- # Backup the original content and the path of the channel-prefs.js file
- self.default_update_channel = {
- 'content': self.software_update.update_channel.file_contents,
- 'path': self.software_update.update_channel.file_path,
- }
- self.software_update.update_channel.default_channel = self.update_channel
-
# 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,
}
@@ -93,19 +80,16 @@ class UpdateTestCase(PuppeteerMixin, Mar
self.updates = [{
'build_pre': self.software_update.build_info,
'build_post': None,
'fallback': is_fallback,
'patch': {},
'success': False,
}]
- self.assertEqual(self.software_update.update_channel.default_channel,
- self.software_update.update_channel.channel)
-
self.assertTrue(self.update_mar_channels.issubset(
self.software_update.mar_channels.channels),
'Allowed MAR channels have been set: expected "{}" in "{}"'.format(
', '.join(self.update_mar_channels),
', '.join(self.software_update.mar_channels.channels)))
# Check if the user has permissions to run the update
self.assertTrue(self.software_update.allowed,
@@ -377,40 +361,31 @@ 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 channel-prefs.js file if modified
- try:
- if self.default_update_channel:
- path = self.default_update_channel['path']
- self.logger.info('Restoring channel defaults for: {}'.format(path))
- with open(path, 'w') as f:
- f.write(self.default_update_channel['content'])
- except IOError:
- self.logger.error('Failed to reset the default update channel.',
- exc_info=True)
-
# 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.puppeteer.prefs.set_pref("app.update.url", self.update_url,
default_branch=True)
def wait_for_download_finished(self, window, timeout=TIMEOUT_UPDATE_DOWNLOAD):
""" Waits until download is completed.
:param window: Instance of :class:`AboutWindow` or :class:`UpdateWizardDialog`.
--- a/testing/firefox-ui/tests/puppeteer/test_software_update.py
+++ b/testing/firefox-ui/tests/puppeteer/test_software_update.py
@@ -12,21 +12,24 @@ from marionette import MarionetteTestCas
class TestSoftwareUpdate(PuppeteerMixin, MarionetteTestCase):
def setUp(self):
super(TestSoftwareUpdate, self).setUp()
self.software_update = SoftwareUpdate(self.marionette)
self.saved_mar_channels = self.software_update.mar_channels.channels
+ self.saved_update_channel = self.software_update.update_channel
+
self.software_update.mar_channels.channels = set(['expected', 'channels'])
def tearDown(self):
try:
self.software_update.mar_channels.channels = self.saved_mar_channels
+ self.software_update.update_channel = self.saved_update_channel
finally:
super(TestSoftwareUpdate, self).tearDown()
def test_abi(self):
self.assertTrue(self.software_update.ABI)
def test_allowed(self):
self.assertTrue(self.software_update.allowed)
@@ -36,17 +39,17 @@ class TestSoftwareUpdate(PuppeteerMixin,
self.assertEqual(build_info['disabled_addons'], None)
self.assertIn('Mozilla/', build_info['user_agent'])
self.assertEqual(build_info['mar_channels'], set(['expected', 'channels']))
self.assertTrue(build_info['version'])
self.assertTrue(build_info['buildid'].isdigit())
self.assertTrue(build_info['locale'])
self.assertIn('force=1', build_info['update_url'])
self.assertIn('xml', build_info['update_snippet'])
- self.assertEqual(build_info['channel'], self.software_update.update_channel.channel)
+ self.assertEqual(build_info['channel'], self.software_update.update_channel)
def test_force_fallback(self):
status_file = os.path.join(self.software_update.staging_directory, 'update.status')
try:
self.software_update.force_fallback()
with open(status_file, 'r') as f:
content = f.read()
@@ -63,42 +66,20 @@ class TestSoftwareUpdate(PuppeteerMixin,
self.assertIn('force=1', update_url)
def test_os_version(self):
self.assertTrue(self.software_update.os_version)
def test_staging_directory(self):
self.assertTrue(self.software_update.staging_directory)
-
-class TestUpdateChannel(PuppeteerMixin, MarionetteTestCase):
-
- def setUp(self):
- super(TestUpdateChannel, self).setUp()
-
- self.software_update = SoftwareUpdate(self.marionette)
-
- self.saved_channel = self.software_update.update_channel.default_channel
- self.software_update.update_channel.default_channel = 'expected_channel'
-
- def tearDown(self):
- try:
- self.software_update.update_channel.default_channel = self.saved_channel
- finally:
- super(TestUpdateChannel, self).tearDown()
-
- def test_update_channel_channel(self):
- self.assertEqual(self.software_update.update_channel.channel, self.saved_channel)
-
- def test_update_channel_default_channel(self):
- self.assertEqual(self.software_update.update_channel.default_channel, 'expected_channel')
-
- def test_update_channel_set_default_channel(self):
- self.software_update.update_channel.default_channel = 'new_channel'
- self.assertEqual(self.software_update.update_channel.default_channel, 'new_channel')
+ def test_set_update_channel(self):
+ self.software_update.update_channel = 'new_channel'
+ self.assertEqual(self.puppeteer.prefs.get_pref('app.update.channel', default_branch=True),
+ 'new_channel')
class TestMARChannels(PuppeteerMixin, MarionetteTestCase):
def setUp(self):
super(TestMARChannels, self).setUp()
self.software_update = SoftwareUpdate(self.marionette)
--- a/testing/puppeteer/firefox/firefox_puppeteer/api/software_update.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/api/software_update.py
@@ -1,14 +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 os
-import re
import mozinfo
from firefox_puppeteer.base import BaseLib
from firefox_puppeteer.api.appinfo import AppInfo
from firefox_puppeteer.api.prefs import Preferences
@@ -159,27 +158,27 @@ class MARChannels(BaseLib):
"""
self.channels = self.channels - set(channels)
class SoftwareUpdate(BaseLib):
"""The SoftwareUpdate API adds support for an easy access to the update process."""
PREF_APP_DISTRIBUTION = 'distribution.id'
PREF_APP_DISTRIBUTION_VERSION = 'distribution.version'
+ PREF_APP_UPDATE_CHANNEL = 'app.update.channel'
PREF_APP_UPDATE_URL = 'app.update.url'
PREF_APP_UPDATE_URL_OVERRIDE = 'app.update.url.override'
PREF_DISABLED_ADDONS = 'extensions.disabledAddons'
def __init__(self, marionette):
BaseLib.__init__(self, marionette)
self.app_info = AppInfo(marionette)
self.prefs = Preferences(marionette)
- self._update_channel = UpdateChannel(marionette)
self._mar_channels = MARChannels(marionette)
self._active_update = ActiveUpdate(marionette)
@property
def ABI(self):
"""Get the customized ABI for the update service.
:returns: ABI version
@@ -219,17 +218,17 @@ class SoftwareUpdate(BaseLib):
"""Return information of the current build version
:returns: A dictionary of build information
"""
update_url = self.get_update_url(True)
return {
'buildid': self.app_info.appBuildID,
- 'channel': self.update_channel.channel,
+ 'channel': self.update_channel,
'disabled_addons': self.prefs.get_pref(self.PREF_DISABLED_ADDONS),
'locale': self.app_info.locale,
'mar_channels': self.mar_channels.channels,
'update_url': update_url,
'update_snippet': self.get_update_snippet(update_url),
'user_agent': self.app_info.user_agent,
'version': self.app_info.version
}
@@ -290,17 +289,17 @@ class SoftwareUpdate(BaseLib):
osVersion = encodeURIComponent(osVersion);
}
return osVersion;
""")
@property
def patch_info(self):
""" Returns information of the active update in the queue."""
- info = {'channel': self.update_channel.channel}
+ info = {'channel': self.update_channel}
if (self.active_update.exists):
info['buildid'] = self.active_update.buildID
info['is_complete'] = self.is_complete_update
info['size'] = self.active_update.selected_patch['size']
info['type'] = self.update_type
info['url_mirror'] = \
self.active_update.selected_patch['finalURL'] or 'n/a'
@@ -314,18 +313,27 @@ class SoftwareUpdate(BaseLib):
return self.marionette.execute_script("""
let aus = Components.classes['@mozilla.org/updates/update-service;1']
.getService(Components.interfaces.nsIApplicationUpdateService);
return aus.getUpdatesDirectory().path;
""")
@property
def update_channel(self):
- """ Holds a reference to an :class:`UpdateChannel` object."""
- return self._update_channel
+ """Return the currently used update channel."""
+ return self.prefs.get_pref(self.PREF_APP_UPDATE_CHANNEL, default_branch=True)
+
+ @update_channel.setter
+ def update_channel(self, channel):
+ """Set the update channel to be used for update checks.
+
+ :param channel: New update channel to use
+
+ """
+ self.prefs.set_pref(self.PREF_APP_UPDATE_CHANNEL, channel, default_branch=True)
@property
def update_type(self):
"""Returns the type of the active update."""
return self.active_update.type
def force_fallback(self):
"""Update the update.status file and set the status to 'failed:6'"""
@@ -368,61 +376,8 @@ class SoftwareUpdate(BaseLib):
if '?' in url:
url += '&'
else:
url += '?'
url += 'force=1'
return url
-
-class UpdateChannel(BaseLib):
- """Class to handle the update channel as listed in channel-prefs.js"""
- REGEX_UPDATE_CHANNEL = re.compile(r'("app\.update\.channel", ")([^"].*)(?=")')
-
- def __init__(self, marionette):
- BaseLib.__init__(self, marionette)
-
- self.prefs = Preferences(marionette)
-
- self.file_path = self.marionette.execute_script("""
- Components.utils.import('resource://gre/modules/Services.jsm');
-
- let file = Services.dirsvc.get('PrfDef', Components.interfaces.nsIFile);
- file.append('channel-prefs.js');
-
- return file.path;
- """)
-
- @property
- def file_contents(self):
- """The contents of the channel-prefs.js file."""
- with open(self.file_path) as f:
- return f.read()
-
- @property
- def channel(self):
- """The name of the update channel as stored in the
- app.update.channel pref."""
- return self.prefs.get_pref('app.update.channel', True)
-
- @property
- def default_channel(self):
- """Get the default update channel
-
- :returns: Current default update channel
- """
- matches = re.search(self.REGEX_UPDATE_CHANNEL, self.file_contents).groups()
- assert len(matches) == 2, 'Update channel value has been found'
-
- return matches[1]
-
- @default_channel.setter
- def default_channel(self, channel):
- """Set default update channel.
-
- :param channel: New default update channel
- """
- assert channel, 'Update channel has been specified'
- new_content = re.sub(
- self.REGEX_UPDATE_CHANNEL, r'\g<1>' + channel, self.file_contents)
- with open(self.file_path, 'w') as f:
- f.write(new_content)