Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
S2-group
GitHub Repository: S2-group/android-runner
Path: blob/master/AndroidRunner/Progress.py
908 views
1
import hashlib
2
import logging
3
import os
4
import sys
5
import ast
6
from random import randint
7
8
import lxml.etree as et
9
10
import paths
11
12
13
class Progress(object):
14
def __init__(self, progress_file=None, config_file=None, config=None, load_progress=None):
15
self.logger = logging.getLogger(self.__class__.__name__)
16
if load_progress:
17
self.progress_xml_file = progress_file
18
self.progress_xml_content = et.parse(self.progress_xml_file).getroot()
19
self.check_config_hash(config_file)
20
else:
21
self.progress_xml_file = os.path.join(paths.OUTPUT_DIR, 'progress.xml')
22
self.progress_xml_content = self.build_progress_xml(config, config_file)
23
self.write_progress_to_file()
24
25
def get_progress_xml_file(self):
26
return self.progress_xml_file
27
28
@staticmethod
29
def file_to_hash(path):
30
with open(path, 'r') as myfile:
31
content_string = myfile.read().replace('\n', '')
32
hashed_string_obj = hashlib.md5(content_string.encode())
33
return hashed_string_obj.hexdigest()
34
35
def check_config_hash(self, config_file):
36
progress_config_hash = self.progress_xml_content.find('configHash').text
37
if progress_config_hash == self.file_to_hash(config_file):
38
return
39
else:
40
print('Current config.json and config.json from progress.xml are not the same, cannot continue')
41
sys.exit()
42
43
def build_progress_xml(self, config, config_file):
44
config_hash_xml = '<configHash>{}</configHash>'.format(self.file_to_hash(config_file))
45
output_dir_xml = '<outputDir>{}</outputDir>'.format(paths.OUTPUT_DIR)
46
runs_to_run_xml = '<runsToRun>{}</runsToRun>'.format(self.build_runs_xml(config))
47
runs_done_xml = '<runsDone></runsDone>'
48
experiment_xml = '<experiment>{}{}{}{}</experiment>'.format(config_hash_xml, output_dir_xml,
49
runs_to_run_xml, runs_done_xml)
50
return et.fromstring(experiment_xml)
51
52
@staticmethod
53
def build_subject_xml(device, path, browser=None, experiment_arg=None):
54
device_xml = '<device>{}</device>'.format(device)
55
path_xml = '<path>{}</path>'.format(path)
56
if browser is not None:
57
browser_xml = '<browser>{}</browser>'.format(browser)
58
return '{}{}{}'.format(device_xml, path_xml, browser_xml)
59
elif experiment_arg is not None:
60
arg_xml = '<arg>{}</arg>'.format(experiment_arg)
61
return '{}{}{}'.format(device_xml, path_xml, arg_xml)
62
else:
63
return '{}{}'.format(device_xml, path_xml)
64
65
def build_runs_xml(self, config):
66
runs_xml = ''
67
run_id = 0
68
for device in config['devices']:
69
current_paths = config.get('paths', []) + config.get('apps', [])
70
for path in current_paths:
71
if config['type'] == 'web':
72
for browser in config['browsers']:
73
subject_xml = self.build_subject_xml(device, path, browser)
74
for run in range(config['repetitions']):
75
runs_xml = runs_xml + '<run runId="{}">{}<runCount>{}</runCount></run>'. \
76
format(run_id, subject_xml, run + 1)
77
run_id += 1
78
elif config['type'] == 'native' and (config.get("experiment_args", []) != []):
79
for experiment_arg in config.get("experiment_args", []):
80
subject_xml = self.build_subject_xml(device, path, experiment_arg=experiment_arg)
81
for run in range(config['repetitions']):
82
runs_xml = runs_xml + '<run runId="{}">{}<runCount>{}</runCount></run>'. \
83
format(run_id, subject_xml, run + 1)
84
run_id += 1
85
else:
86
subject_xml = self.build_subject_xml(device, path)
87
for run in range(config['repetitions']):
88
runs_xml = runs_xml + '<run runId="{}">{}<runCount>{}</runCount></run>'. \
89
format(run_id, subject_xml, run + 1)
90
run_id += 1
91
92
return runs_xml
93
94
def write_progress_to_file(self):
95
xml = self.progress_xml_content.getroottree()
96
xml.write(self.progress_xml_file, pretty_print=True)
97
98
def get_output_dir(self):
99
return self.progress_xml_content.find('outputDir').text
100
101
"""Get a random run from the <runsToRuns> element"""
102
103
def get_random_run(self):
104
runs_to_run = self.progress_xml_content.find('runsToRun')
105
count = len(runs_to_run.getchildren())
106
random_index = randint(0, count - 1)
107
next_run_xml = self.progress_xml_content.find('runsToRun')[random_index]
108
return self.run_to_dict(next_run_xml)
109
110
"""Get the top run of the list"""
111
112
def get_next_run(self):
113
next_run_xml = self.progress_xml_content.find('runsToRun')[0] # First run in list
114
return self.run_to_dict(next_run_xml)
115
116
"""Turn a <run> element and its childeren into a dictionary"""
117
118
def run_to_dict(self, run_xml):
119
run = dict()
120
run['runId'] = run_xml.get('runId')
121
run['device'] = run_xml.find('device').text
122
run['path'] = run_xml.find('path').text
123
run['runCount'] = self.get_run_count(run_xml, run['device'], run['path'])
124
browser = run_xml.find('browser')
125
if browser is not None:
126
run['browser'] = run_xml.find('browser').text
127
128
arg = run_xml.find("arg")
129
if arg is not None:
130
try:
131
arg = ast.literal_eval(run_xml.find("arg").text)
132
except:
133
arg = run_xml.find("arg").text
134
run["experimentArg"] = arg
135
136
return run
137
138
def get_run_count(self, run_xml, device, path):
139
runs_done = self.progress_xml_content.find('runsDone')
140
browser_val = run_xml.find('browser')
141
arg_val = run_xml.find('arg')
142
if browser_val is not None:
143
browser_name = browser_val.text
144
query = "run[device='{}' and path='{}' and browser='{}']".format(device, path, browser_name)
145
elif arg_val is not None:
146
arg_val = arg_val.text
147
query = "run[device='{}' and path='{}' and arg='{}']".format(device, path, arg_val)
148
else:
149
query = "run[device='{}' and path='{}']".format(device, path)
150
elements = runs_done.xpath(query)
151
return len(elements) + 1
152
153
"""Marks run as finished"""
154
155
def run_finished(self, run_id):
156
runs_to_run = self.progress_xml_content.find('runsToRun')
157
runs_done = self.progress_xml_content.find('runsDone')
158
elements = runs_to_run.findall("run[@runId='{}']".format(run_id))
159
for el in elements:
160
runs_to_run.remove(el)
161
runs_done.append(el)
162
163
"""Check if this subject already had it's first run"""
164
165
def subject_first(self, device, path, browser=None):
166
runs_done = self.progress_xml_content.find('runsDone')
167
if browser is not None:
168
elements = runs_done.xpath(
169
"run[device='{}' and path='{}' and browser='{}']".format(device, path, browser))
170
else:
171
elements = runs_done.xpath(
172
"run[device='{}' and path='{}']".format(device, path))
173
if not elements:
174
return True
175
else:
176
return False
177
178
"""Checks if all subject runs are done"""
179
180
def subject_finished(self, device, path, browser=None):
181
runs_to_run = self.progress_xml_content.find('runsToRun')
182
if browser is not None:
183
elements = runs_to_run.xpath(
184
"run[device='{}' and path='{}' and browser='{}']".format(device, path, browser))
185
else:
186
elements = runs_to_run.xpath(
187
"run[device='{}' and path='{}']".format(device, path))
188
if not elements:
189
return True
190
else:
191
return False
192
193
"""Check if this device already had it's first run"""
194
195
def device_first(self, device):
196
runs_done = self.progress_xml_content.find('runsDone')
197
elements = runs_done.xpath("run[device='{}']".format(device))
198
199
if not elements:
200
return True
201
else:
202
return False
203
204
"""Checks if all device runs are done"""
205
206
def device_finished(self, device):
207
runs_to_run = self.progress_xml_content.find('runsToRun')
208
elements = runs_to_run.xpath("run[device='{}']".format(device))
209
210
if not elements:
211
return True
212
else:
213
return False
214
215
def experiment_finished_check(self):
216
runs_to_run = self.progress_xml_content.find('runsToRun')
217
count = len(runs_to_run.getchildren())
218
if count == 0:
219
return True
220
else:
221
return False
222
223