Bug 1445944 - [mozprofile] Create a new ChromeProfile class for managing chrome profiles
In Chrome it doesn't seem to be possible to install extensions by dropping them
in the profile directory. Instead we use the --load-extension command line
argument. To that end the ChromeProfile uses a 'dummy' AddonManager() class
that is actually just a list with an 'install' method. Mozrunner will be
responsible for building the command line based on this list.
We also need a few other command line arguments to build and create a temporary
profile directory.
MozReview-Commit-ID: HC2p2ZZMl66
--- a/testing/mozbase/mozprofile/mozprofile/profile.py
+++ b/testing/mozbase/mozprofile/mozprofile/profile.py
@@ -1,29 +1,32 @@
# 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/.
from __future__ import absolute_import
+import json
import os
import platform
import tempfile
import time
import uuid
from abc import ABCMeta, abstractmethod
from shutil import copytree
import mozfile
+from six import string_types
from .addons import AddonManager
from .permissions import Permissions
from .prefs import Preferences
__all__ = ['BaseProfile',
+ 'ChromeProfile',
'Profile',
'FirefoxProfile',
'ThunderbirdProfile',
'create_profile']
class BaseProfile(object):
__metaclass__ = ABCMeta
@@ -438,17 +441,53 @@ class ThunderbirdProfile(Profile):
'browser.tabs.warnOnClose': False,
'browser.warnOnQuit': False,
'browser.sessionstore.resume_from_crash': False,
# prevents the 'new e-mail address' wizard on new profile
'mail.provider.enabled': False,
}
+class ChromeProfile(BaseProfile):
+ class AddonManager(list):
+ def install(self, addons):
+ if isinstance(addons, string_types):
+ addons = [addons]
+ self.extend(addons)
+
+ def __init__(self, **kwargs):
+ super(ChromeProfile, self).__init__(**kwargs)
+
+ if self.create_new:
+ self.profile = os.path.join(self.profile, 'Default')
+ self._reset()
+
+ def _reset(self):
+ if not os.path.isdir(self.profile):
+ os.makedirs(self.profile)
+
+ if self._preferences:
+ pref_file = os.path.join(self.profile, 'Preferences')
+
+ prefs = {}
+ if os.path.isfile(pref_file):
+ with open(pref_file, 'r') as fh:
+ prefs.update(json.load(fh))
+
+ prefs.update(self._preferences)
+ with open(pref_file, 'w') as fh:
+ json.dump(prefs, fh)
+
+ self.addons = self.AddonManager()
+ if self._addons:
+ self.addons.install(self._addons)
+
+
profile_class = {
+ 'chrome': ChromeProfile,
'firefox': FirefoxProfile,
'thunderbird': ThunderbirdProfile,
}
def create_profile(app, **kwargs):
"""Create a profile given an application name.
--- a/testing/mozbase/mozprofile/tests/manifest.ini
+++ b/testing/mozbase/mozprofile/tests/manifest.ini
@@ -5,8 +5,9 @@ subsuite = mozbase, os == "linux"
[test_preferences.py]
[test_permissions.py]
[test_bug758250.py]
[test_nonce.py]
[test_clone_cleanup.py]
[test_profile.py]
[test_profile_view.py]
[test_addons.py]
+[test_chrome_profile.py]
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozprofile/tests/test_chrome_profile.py
@@ -0,0 +1,75 @@
+# 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/.
+
+from __future__ import absolute_import
+
+import json
+import os
+
+import mozunit
+
+from mozprofile import ChromeProfile
+
+
+def test_chrome_profile_pre_existing(tmpdir):
+ path = tmpdir.strpath
+ profile = ChromeProfile(profile=path)
+ assert not profile.create_new
+ assert os.path.isdir(profile.profile)
+ assert profile.profile == path
+
+
+def test_chrome_profile_create_new():
+ profile = ChromeProfile()
+ assert profile.create_new
+ assert os.path.isdir(profile.profile)
+ assert profile.profile.endswith('Default')
+
+
+def test_chrome_preferences(tmpdir):
+ prefs = {'foo': 'bar'}
+ profile = ChromeProfile(preferences=prefs)
+ prefs_file = os.path.join(profile.profile, 'Preferences')
+
+ assert os.path.isfile(prefs_file)
+
+ with open(prefs_file) as fh:
+ assert json.load(fh) == prefs
+
+ # test with existing prefs
+ prefs_file = tmpdir.join('Preferences').strpath
+ with open(prefs_file, 'w') as fh:
+ json.dump({'num': '1'}, fh)
+
+ profile = ChromeProfile(profile=tmpdir.strpath, preferences=prefs)
+
+ def assert_prefs():
+ with open(prefs_file) as fh:
+ data = json.load(fh)
+
+ assert len(data) == 2
+ assert data.get('foo') == 'bar'
+ assert data.get('num') == '1'
+
+ assert_prefs()
+ profile.reset()
+ assert_prefs()
+
+
+def test_chrome_addons():
+ addons = ['foo', 'bar']
+ profile = ChromeProfile(addons=addons)
+
+ assert isinstance(profile.addons, list)
+ assert profile.addons == addons
+
+ profile.addons.install('baz')
+ assert profile.addons == addons + ['baz']
+
+ profile.reset()
+ assert profile.addons == addons
+
+
+if __name__ == '__main__':
+ mozunit.main()
--- a/testing/mozbase/mozprofile/tests/test_profile.py
+++ b/testing/mozbase/mozprofile/tests/test_profile.py
@@ -9,16 +9,17 @@ from __future__ import absolute_import
import os
import mozunit
import pytest
from mozprofile import (
BaseProfile,
Profile,
+ ChromeProfile,
FirefoxProfile,
ThunderbirdProfile,
create_profile,
)
def test_with_profile_should_cleanup():
with Profile() as profile:
@@ -34,16 +35,17 @@ def test_with_profile_should_cleanup_eve
assert os.path.exists(profile.profile)
1 / 0 # will raise ZeroDivisionError
# profile is cleaned
assert not os.path.exists(profile.profile)
@pytest.mark.parametrize('app,cls', [
+ ('chrome', ChromeProfile),
('firefox', FirefoxProfile),
('thunderbird', ThunderbirdProfile),
('unknown', None)
])
def test_create_profile(tmpdir, app, cls):
path = tmpdir.strpath
if cls is None:
--- a/testing/mozbase/mozrunner/mozrunner/application.py
+++ b/testing/mozbase/mozrunner/mozrunner/application.py
@@ -7,16 +7,17 @@ from __future__ import absolute_import
from abc import ABCMeta, abstractmethod
from distutils.spawn import find_executable
import os
import posixpath
from mozdevice import DeviceManagerADB, DroidADB
from mozprofile import (
Profile,
+ ChromeProfile,
FirefoxProfile,
ThunderbirdProfile
)
here = os.path.abspath(os.path.dirname(__file__))
def get_app_context(appname):
@@ -131,14 +132,10 @@ class FennecContext(RemoteContext):
class FirefoxContext(object):
profile_class = FirefoxProfile
class ThunderbirdContext(object):
profile_class = ThunderbirdProfile
-class ChromeProfile(object):
- """Dummy profile class until a proper one is implemented in mozprofile"""
-
-
class ChromeContext(object):
profile_class = ChromeProfile
--- a/testing/mozbase/mozrunner/mozrunner/base/browser.py
+++ b/testing/mozbase/mozrunner/mozrunner/base/browser.py
@@ -81,15 +81,25 @@ class GeckoRuntimeRunner(BaseRunner):
class BlinkRuntimeRunner(BaseRunner):
"""A base runner class for running apps like Google Chrome or Chromium."""
def __init__(self, binary, cmdargs=None, **runner_args):
super(BlinkRuntimeRunner, self).__init__(**runner_args)
self.binary = binary
self.cmdargs = cmdargs or []
+ data_dir, name = os.path.split(self.profile.profile)
+ profile_args = [
+ '--user-data-dir={}'.format(data_dir),
+ '--profile-directory={}'.format(name),
+ '--no-first-run',
+ ]
+ self.cmdargs.extend(profile_args)
+
@property
def command(self):
cmd = self.cmdargs[:]
+ if self.profile.addons:
+ cmd.append('--load-extension={}'.format(','.join(self.profile.addons)))
return [self.binary] + cmd
def check_for_crashes(self, *args, **kwargs):
raise NotImplementedError