~canonical-platform-qa/ubuntu-system-tests/fix-wizard-reporting-page

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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-

#
# Ubuntu System Tests
# Copyright (C) 2014 Canonical
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import dbus
import logging
import re
import subprocess

from ubuntu_system_tests.helpers import wait_until

logger = logging.getLogger(__name__)

SIM_MANAGER = 'org.ofono.SimManager'
NETWORK_REGISTER_TIMEOUT = 180


def _get_sim_manager(sim_number):
    bus = dbus.SystemBus()
    modem = bus.get_object('org.ofono', '/ril_{}'.format(sim_number))
    return dbus.Interface(modem, SIM_MANAGER)


def is_pin_locked(sim_number):
    sim_manager = _get_sim_manager(sim_number)
    locked_pins = sim_manager.GetProperties()['LockedPins']
    return 'pin' in locked_pins


def unlock_sim(sim_number, pin):
    sim_manager = _get_sim_manager(sim_number)
    if is_pin_locked(sim_number):
        sim_manager.UnlockPin('pin', pin)


def lock_sim(sim_number, pin):
    sim_manager = _get_sim_manager(sim_number)
    if not is_pin_locked(sim_number):
        sim_manager.LockPin('pin', pin)


def _check_modem(ril_modem, properties, modem_number=None,
                 ignore_phonesim=True):
    """Decide if the specified modem should be checked.

    Returns True if this modem should be checked, False if not.

    :param ignore_phonesim: If true then phonesim modems will be ignored.
    :param properties: Properties from the modem
    :param ril_modem: Name of the modem
    :parm modem_number: Number of specific modem to check, or None to check all
    :returns: True if this modem should be checked, False if not.
    """
    PHONESIM_SERIAL = '000000000000000'
    if (str(ril_modem).endswith(str(modem_number)) or modem_number is None):
        if 'Serial' not in properties:
            # This is not a real modem, ignore it
            check_status = False
        elif ignore_phonesim and properties['Serial'] == PHONESIM_SERIAL:
            # This is a phonesim modem and should be ignored
            check_status = False
        else:
            # This modem should be checked
            check_status = True
    else:
        check_status = False
    return check_status


def _get_all_modems(bus):
    """
    Get the DBus interfaces representing each modem
    the device has.

    :returns: A list of modems
    """
    manager = dbus.Interface(
        bus.get_object('org.ofono', '/'), 'org.ofono.Manager')
    return manager.GetModems()


def _sim_present(bus, ril_modem, properties,
                 sim_number=None, ignore_phonesim=True):
    if _check_modem(ril_modem, properties, modem_number=sim_number,
                    ignore_phonesim=ignore_phonesim):
        modem = bus.get_object('org.ofono', ril_modem)
        sim_manager = dbus.Interface(modem, SIM_MANAGER)
        try:
            if sim_manager.GetProperties()['Present']:
                return True
        except dbus.exceptions.DBusException as e:
            logger.warning('exception: {0}detected on modem: {1}'.format(
                           e, ril_modem))
    return False


def is_sim_inserted(sim_number=None, ignore_phonesim=True):
    """Check a SIM is inserted.

    Checks if a SIM card is inserted in the specified
    slot on the device. If no slot is specified then
    all slots will be checked.

    :param ignore_phonesim: If true then phonesim modems will be ignored.
    :param sim_number: The slot index to check for SIM presence

    :returns: True if a SIM is inserted in the specified slot or
    if no slot is specified then if a SIM is inserted in
    any slot, otherwise False
    """
    bus = dbus.SystemBus()
    for ril_modem, properties in _get_all_modems(bus):
        if _sim_present(bus, ril_modem, properties,
                        sim_number, ignore_phonesim):
            return True
    return False


def number_of_sims(ignore_phonesim=True):
    """
    Provide the number of SIMs inserted in the device.

    :returns: The number of SIMs found
    """
    number_of_sims = 0
    bus = dbus.SystemBus()
    for ril_modem, properties in _get_all_modems(bus):
        if _sim_present(bus, ril_modem, properties,
                        ignore_phonesim=ignore_phonesim):
            number_of_sims += 1
    return number_of_sims


def get_sim_name(sim_slot_index=0):
    """
    Provide the network name of the SIM inserted in the device.

    :param sim_slot_index: the index number of the SIM slot
    :return: The network name of the SIM
    """
    account_names = _get_ofono_account_names()
    for account_name in account_names:
        if _is_account_associated(account_name, sim_slot_index):
            return _get_network_name(account_name)


def _get_network_registration_interface(bus, modem):
    """
    Return NetworkRegistration interface for specified modem.

    :param bus: DBus System bus object.
    :param modem: Path of modem to check
    :return: NetworkRegistration interface object.

    """
    modem = bus.get_object('org.ofono', modem)
    return dbus.Interface(modem, 'org.ofono.NetworkRegistration')


def _get_registered_status_for_modem(bus, ril_modem):
    """
    Return Boolean network registration status for specified modem.

    :param bus: DBus System bus object.
    :param modem: Path of modem to check
    :return: True if registered, False otherwise.

    """
    try:
        interface = _get_network_registration_interface(bus, ril_modem)
        if interface.GetProperties()['Status'] == 'registered':
            return True
    except dbus.exceptions.DBusException:
        pass
    return False


def is_sim_registered(sim_number):
    """
    Return True if the specified SIM is registered on a mobile network.

    :param sim_number: String number for the required SIM. Either '0', '1'.
    :return: True if registered on network, False otherwise.

    """
    bus = dbus.SystemBus()
    ril_modem = '/ril_{}'.format(sim_number)
    return _get_registered_status_for_modem(bus, ril_modem)


def is_any_sim_registered():
    """Return True if any available SIM is registered on a mobile network."""
    if is_sim_inserted():
        bus = dbus.SystemBus()
        for ril_modem, properties in _get_all_modems(bus):
            if _get_registered_status_for_modem(bus, ril_modem):
                return True
    return False


def are_all_sims_registered():
    """Return True if all available SIMs are registered on a mobile network."""
    if is_sim_inserted():
        bus = dbus.SystemBus()
        for ril_modem, properties in _get_all_modems(bus):
            if (_sim_present(bus, ril_modem, properties) and
               not _get_registered_status_for_modem(bus, ril_modem)):
                return False
        return True
    return False


def wait_for_sim_registered(sim, timeout=NETWORK_REGISTER_TIMEOUT):
    """
    Wait until the specified SIM is registered on the network.

    :param sim: String number for the required SIM. Either '0', '1'.
    :param timeout: How long to wait before timing out.
    :return: True if registered on network, False otherwise.

    """
    return wait_until(is_sim_registered, sim, timeout=timeout)


def wait_for_any_sim_registered(timeout=NETWORK_REGISTER_TIMEOUT):
    """
    Wait until any available SIM is registered on the network.

    :param timeout: How long to wait before timing out.
    :return: True if any SIM registered on network, False otherwise.

    """
    return wait_until(is_any_sim_registered, timeout=timeout)


def wait_for_all_sims_registered(timeout=NETWORK_REGISTER_TIMEOUT):
    """
    Wait until all available SIMs are registered on the network.

    :param timeout: How long to wait before timing out.
    :return: True if all available SIMs registered on network, False otherwise.

    """
    return wait_until(are_all_sims_registered, timeout=timeout)


def _get_ofono_account_names():
    """Returns a list, containing low-level names of ofono accounts."""
    names = subprocess.check_output(['mc-tool', 'list'],
                                    universal_newlines=True)
    return [name for name in names.splitlines()]


def _is_account_associated(account_name, slot_index):
    """
    Check if the given ofono account is associated with the
    given SIM slot.

    :param account_name: ofono account name
    :param slot_index: Index number of the SIM slot
    :return: True if the given account is associated with the
    given SIM card slot, otherwise False
    """
    account_details = _get_details_for_account(account_name)
    for line in account_details:
        if '/ril_{}'.format(slot_index) in line:
            return True
    return False


def _get_network_name(account_name):
    """
    Provide cellular provider name of the given account
    :param account_name: ofono account name
    :return: The name of the cellular network associated with the given
    ofono account
    """
    account_details = _get_details_for_account(account_name)
    for line in account_details:
        if 'Current:' in line:
            return re.findall(r'"([^"]*)"', line)[0]


def _get_details_for_account(account_name):
    """
    Provide all available details about a specific ofono account.
    :param account_name: ofono account name
    :return: A list of characteristics and properties of the
    relevant ofono account
    """
    details = subprocess.check_output(['mc-tool', 'show', account_name],
                                      universal_newlines=True)
    return [line for line in details.splitlines()]


def end_call():
    """Programmatically end all ongoing calls."""
    bus = dbus.SystemBus()
    for path, properties in _get_all_modems(bus):
        if 'org.ofono.VoiceCallManager' in properties['Interfaces']:
            mgr = dbus.Interface(
                bus.get_object('org.ofono', path),
                'org.ofono.VoiceCallManager')
            for call_path, properties in mgr.GetCalls():
                subprocess.call(
                    ['/usr/share/ofono/scripts/hangup-call', call_path])