Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
S2-group
GitHub Repository: S2-group/android-runner
Path: blob/master/AndroidRunner/Script.py
629 views
1
import logging
2
import multiprocessing as mp
3
import os.path as op
4
import signal
5
import time
6
from . import Tests
7
from .util import FileNotFoundError
8
9
10
class ScriptError(Exception):
11
pass
12
13
14
class Script(object):
15
def __init__(self, path, timeout=0, logcat_regex=None):
16
self.logger = logging.getLogger(self.__class__.__name__)
17
self.path = path
18
if not op.isfile(path):
19
raise FileNotFoundError(path)
20
self.filename = op.basename(path)
21
self.timeout = float(Tests.is_integer(timeout)) / 1000
22
self.logcat_event = logcat_regex
23
if logcat_regex is not None:
24
self.logcat_event = Tests.is_string(logcat_regex)
25
26
def execute_script(self, device, *args, **kwargs):
27
"""The method that is extended to execute the script"""
28
self.logger.info(self.filename)
29
30
def mp_run(self, queue, device, *args, **kwargs):
31
"""The multiprocessing wrapper of execute_script()"""
32
try:
33
output = self.execute_script(device, *args, **kwargs)
34
self.logger.debug('%s returned %s' % (self.filename, output))
35
except Exception as e:
36
import traceback
37
queue.put((e, traceback.format_exc()))
38
queue.put('script')
39
40
@staticmethod
41
def mp_logcat_regex(queue, device, regex):
42
"""The multiprocessing wrapper of Device.logcat_regex()"""
43
# https://stackoverflow.com/a/21936682
44
# pyadb uses subprocess.communicate(), therefore it blocks
45
while not device.logcat_regex(regex):
46
time.sleep(1)
47
queue.put('logcat')
48
49
def run(self, device, *args, **kwargs):
50
"""Execute the script with respect to the termination conditions"""
51
# https://stackoverflow.com/a/6286343
52
with script_timeout(seconds=self.timeout):
53
processes = []
54
try:
55
queue = mp.Queue()
56
processes.append(mp.Process(target=self.mp_run, args=(queue, device,) + args, kwargs=kwargs))
57
if self.logcat_event is not None and device is not None:
58
processes.append(mp.Process(target=self.mp_logcat_regex, args=(queue, device, self.logcat_event)))
59
for p in processes:
60
p.start()
61
result = queue.get()
62
if isinstance(result, tuple):
63
name = result[0].__class__.__name__
64
message = str(result[0])
65
trace = result[1]
66
log_message = '%s in %s: %s\n%s' % (name, self.filename, message, trace)
67
# self.logger.error(log_message)
68
raise ScriptError(log_message)
69
except TimeoutError:
70
self.logger.debug('Interaction function timeout (%sms)' % self.timeout)
71
result = 'timeout'
72
finally:
73
for p in processes:
74
p.terminate()
75
return result
76
77
78
class TimeoutError(Exception):
79
pass
80
81
82
# https://stackoverflow.com/a/22348885
83
class script_timeout:
84
def __init__(self, seconds):
85
self.seconds = float(seconds)
86
87
def handle_timeout(self, signum, frame):
88
raise TimeoutError()
89
90
def __enter__(self):
91
if self.seconds != 0:
92
signal.signal(signal.SIGALRM, self.handle_timeout)
93
signal.setitimer(signal.ITIMER_REAL, self.seconds)
94
95
def __exit__(self, type, value, traceback):
96
if self.seconds != 0:
97
signal.alarm(0)
98
99