summaryrefslogtreecommitdiffstats
path: root/testing/mozbase/mozrunner/mozrunner/application.py
blob: bbafa9ff5a8be2ed313e2dd4b034addd92442c68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# 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 posixpath
from abc import ABCMeta, abstractmethod
from shutil import which

import six
from mozdevice import ADBDeviceFactory
from mozprofile import (
    ChromeProfile,
    ChromiumProfile,
    FirefoxProfile,
    Profile,
    ThunderbirdProfile,
)

here = os.path.abspath(os.path.dirname(__file__))


def get_app_context(appname):
    context_map = {
        "chrome": ChromeContext,
        "chromium": ChromiumContext,
        "default": DefaultContext,
        "fennec": FennecContext,
        "firefox": FirefoxContext,
        "thunderbird": ThunderbirdContext,
    }
    if appname not in context_map:
        raise KeyError("Application '%s' not supported!" % appname)
    return context_map[appname]


class DefaultContext(object):
    profile_class = Profile


@six.add_metaclass(ABCMeta)
class RemoteContext(object):
    device = None
    _remote_profile = None
    _adb = None
    profile_class = Profile
    _bindir = None
    remote_test_root = ""
    remote_process = None

    @property
    def bindir(self):
        if self._bindir is None:
            paths = [which("emulator")]
            paths = [p for p in paths if p is not None if os.path.isfile(p)]
            if not paths:
                self._bindir = ""
            else:
                self._bindir = os.path.dirname(paths[0])
        return self._bindir

    @property
    def adb(self):
        if not self._adb:
            paths = [
                os.environ.get("ADB"),
                os.environ.get("ADB_PATH"),
                self.which("adb"),
            ]
            paths = [p for p in paths if p is not None if os.path.isfile(p)]
            if not paths:
                raise OSError(
                    "Could not find the adb binary, make sure it is on your"
                    "path or set the $ADB_PATH environment variable."
                )
            self._adb = paths[0]
        return self._adb

    @property
    def remote_profile(self):
        if not self._remote_profile:
            self._remote_profile = posixpath.join(self.remote_test_root, "profile")
        return self._remote_profile

    def which(self, binary):
        paths = os.environ.get("PATH", {}).split(os.pathsep)
        if self.bindir is not None and os.path.abspath(self.bindir) not in paths:
            paths.insert(0, os.path.abspath(self.bindir))
            os.environ["PATH"] = os.pathsep.join(paths)

        return which(binary)

    @abstractmethod
    def stop_application(self):
        """Run (device manager) command to stop application."""
        pass


devices = {}


class FennecContext(RemoteContext):
    _remote_profiles_ini = None
    _remote_test_root = None

    def __init__(self, app=None, adb_path=None, avd_home=None, device_serial=None):
        self._adb = adb_path
        self.avd_home = avd_home
        self.remote_process = app
        self.device_serial = device_serial
        self.device = self.get_device(self.adb, device_serial)

    def get_device(self, adb_path, device_serial):
        # Create a mozdevice.ADBDevice object for the specified device_serial
        # and cache it for future use. If the same device_serial is subsequently
        # requested, retrieve it from the cache to avoid costly re-initialization.
        global devices
        if device_serial in devices:
            device = devices[device_serial]
        else:
            device = ADBDeviceFactory(adb=adb_path, device=device_serial)
            devices[device_serial] = device
        return device

    def stop_application(self):
        self.device.stop_application(self.remote_process)

    @property
    def remote_test_root(self):
        if not self._remote_test_root:
            self._remote_test_root = self.device.test_root
        return self._remote_test_root

    @property
    def remote_profiles_ini(self):
        if not self._remote_profiles_ini:
            self._remote_profiles_ini = posixpath.join(
                "/data", "data", self.remote_process, "files", "mozilla", "profiles.ini"
            )
        return self._remote_profiles_ini


class FirefoxContext(object):
    profile_class = FirefoxProfile


class ThunderbirdContext(object):
    profile_class = ThunderbirdProfile


class ChromeContext(object):
    profile_class = ChromeProfile


class ChromiumContext(object):
    profile_class = ChromiumProfile