blob: 8f0604984ccfa378f14fe33a50ccf04729241269 [file] [log] [blame]
lmr6f80e7a2010-02-04 03:18:28 +00001import os
jadmanskicc549172008-05-21 18:11:51 +00002
3from autotest_lib.client.common_lib import utils
4from autotest_lib.tko import utils as tko_utils
jadmanski6e8bf752008-05-14 00:17:48 +00005
6
mblighe79ebb02008-04-17 15:39:22 +00007class job(object):
jadmanskif7fa2cc2008-10-01 14:13:23 +00008 def __init__(self, dir, user, label, machine, queued_time, started_time,
showard71b94312009-08-20 23:40:02 +00009 finished_time, machine_owner, machine_group, aborted_by,
showardc1a98d12010-01-15 00:22:22 +000010 aborted_on, keyval_dict):
jadmanski0afbb632008-06-06 21:10:57 +000011 self.dir = dir
12 self.tests = []
13 self.user = user
14 self.label = label
15 self.machine = machine
16 self.queued_time = queued_time
17 self.started_time = started_time
18 self.finished_time = finished_time
19 self.machine_owner = machine_owner
showard71b94312009-08-20 23:40:02 +000020 self.machine_group = machine_group
jadmanskif7fa2cc2008-10-01 14:13:23 +000021 self.aborted_by = aborted_by
22 self.aborted_on = aborted_on
showardc1a98d12010-01-15 00:22:22 +000023 self.keyval_dict = keyval_dict
mblighe79ebb02008-04-17 15:39:22 +000024
25
jadmanskia8e302a2008-09-25 19:49:38 +000026 @staticmethod
27 def read_keyval(dir):
28 dir = os.path.normpath(dir)
29 top_dir = tko_utils.find_toplevel_job_dir(dir)
30 if not top_dir:
31 top_dir = dir
32 assert(dir.startswith(top_dir))
33
34 # pull in and merge all the keyval files, with higher-level
35 # overriding values in the lower-level ones
36 keyval = {}
37 while True:
38 try:
jadmanskifc4e3382008-10-02 16:19:19 +000039 upper_keyval = utils.read_keyval(dir)
40 # HACK: exclude hostname from the override - this is a special
41 # case where we want lower to override higher
42 if "hostname" in upper_keyval and "hostname" in keyval:
43 del upper_keyval["hostname"]
jadmanski8e00afa2008-10-02 16:22:04 +000044 keyval.update(upper_keyval)
jadmanskia8e302a2008-09-25 19:49:38 +000045 except IOError:
46 pass # if the keyval can't be read just move on to the next
47 if dir == top_dir:
48 break
49 else:
50 assert(dir != "/")
51 dir = os.path.dirname(dir)
52 return keyval
53
54
55
mblighe79ebb02008-04-17 15:39:22 +000056class kernel(object):
jadmanski0afbb632008-06-06 21:10:57 +000057 def __init__(self, base, patches, kernel_hash):
58 self.base = base
59 self.patches = patches
60 self.kernel_hash = kernel_hash
mblighe79ebb02008-04-17 15:39:22 +000061
62
jadmanski0afbb632008-06-06 21:10:57 +000063 @staticmethod
64 def compute_hash(base, hashes):
65 key_string = ','.join([base] + hashes)
lmr6f80e7a2010-02-04 03:18:28 +000066 return utils.hash('md5', key_string).hexdigest()
jadmanski6e8bf752008-05-14 00:17:48 +000067
68
mblighe79ebb02008-04-17 15:39:22 +000069class test(object):
jadmanski0afbb632008-06-06 21:10:57 +000070 def __init__(self, subdir, testname, status, reason, test_kernel,
71 machine, started_time, finished_time, iterations,
jadmanski9b6babf2009-04-21 17:57:40 +000072 attributes, labels):
jadmanski0afbb632008-06-06 21:10:57 +000073 self.subdir = subdir
74 self.testname = testname
75 self.status = status
76 self.reason = reason
77 self.kernel = test_kernel
78 self.machine = machine
79 self.started_time = started_time
80 self.finished_time = finished_time
81 self.iterations = iterations
82 self.attributes = attributes
jadmanski9b6babf2009-04-21 17:57:40 +000083 self.labels = labels
mblighe79ebb02008-04-17 15:39:22 +000084
85
jadmanski0afbb632008-06-06 21:10:57 +000086 @staticmethod
87 def load_iterations(keyval_path):
88 """Abstract method to load a list of iterations from a keyval
89 file."""
90 raise NotImplementedError
jadmanskicc549172008-05-21 18:11:51 +000091
92
jadmanski0afbb632008-06-06 21:10:57 +000093 @classmethod
94 def parse_test(cls, job, subdir, testname, status, reason, test_kernel,
jadmanski74eebf32008-07-15 20:04:42 +000095 started_time, finished_time, existing_instance=None):
jadmanski0afbb632008-06-06 21:10:57 +000096 """Given a job and the basic metadata about the test that
97 can be extracted from the status logs, parse the test
98 keyval files and use it to construct a complete test
99 instance."""
100 tko_utils.dprint("parsing test %s %s" % (subdir, testname))
jadmanskicc549172008-05-21 18:11:51 +0000101
jadmanski0afbb632008-06-06 21:10:57 +0000102 if subdir:
103 # grab iterations from the results keyval
104 iteration_keyval = os.path.join(job.dir, subdir,
105 "results", "keyval")
106 iterations = cls.load_iterations(iteration_keyval)
jadmanskicc549172008-05-21 18:11:51 +0000107
jadmanski0afbb632008-06-06 21:10:57 +0000108 # grab test attributes from the subdir keyval
109 test_keyval = os.path.join(job.dir, subdir, "keyval")
110 attributes = test.load_attributes(test_keyval)
111 else:
112 iterations = []
113 attributes = {}
jadmanskicc549172008-05-21 18:11:51 +0000114
jadmanskib591fba2008-09-10 16:19:22 +0000115 # grab test+host attributes from the host keyval
showard71b94312009-08-20 23:40:02 +0000116 host_keyval = cls.parse_host_keyval(job.dir, job.machine)
117 attributes.update(dict(("host-%s" % k, v)
118 for k, v in host_keyval.iteritems()))
jadmanskib591fba2008-09-10 16:19:22 +0000119
jadmanski74eebf32008-07-15 20:04:42 +0000120 if existing_instance:
121 def constructor(*args, **dargs):
122 existing_instance.__init__(*args, **dargs)
123 return existing_instance
124 else:
125 constructor = cls
126 return constructor(subdir, testname, status, reason, test_kernel,
127 job.machine, started_time, finished_time,
jadmanski9b6babf2009-04-21 17:57:40 +0000128 iterations, attributes, [])
jadmanski74eebf32008-07-15 20:04:42 +0000129
130
131 @classmethod
132 def parse_partial_test(cls, job, subdir, testname, reason, test_kernel,
133 started_time):
134 """Given a job and the basic metadata available when a test is
135 started, create a test instance representing the partial result.
136 Assume that since the test is not complete there are no results files
137 actually available for parsing."""
138 tko_utils.dprint("parsing partial test %s %s" % (subdir, testname))
139
140 return cls(subdir, testname, "RUNNING", reason, test_kernel,
jadmanski9b6babf2009-04-21 17:57:40 +0000141 job.machine, started_time, None, [], {}, [])
jadmanskicc549172008-05-21 18:11:51 +0000142
143
jadmanski0afbb632008-06-06 21:10:57 +0000144 @staticmethod
145 def load_attributes(keyval_path):
146 """Load the test attributes into a dictionary from a test
147 keyval path. Does not assume that the path actually exists."""
148 if not os.path.exists(keyval_path):
149 return {}
150 return utils.read_keyval(keyval_path)
jadmanskicc549172008-05-21 18:11:51 +0000151
152
jadmanskib591fba2008-09-10 16:19:22 +0000153 @staticmethod
154 def parse_host_keyval(job_dir, hostname):
155 # the "real" job dir may be higher up in the directory tree
jadmanskia8e302a2008-09-25 19:49:38 +0000156 job_dir = tko_utils.find_toplevel_job_dir(job_dir)
157 if not job_dir:
158 return {} # we can't find a top-level job dir with host keyvals
jadmanskib591fba2008-09-10 16:19:22 +0000159
160 # the keyval is <job_dir>/host_keyvals/<hostname> if it exists
161 keyval_path = os.path.join(job_dir, "host_keyvals", hostname)
162 if os.path.isfile(keyval_path):
showard71b94312009-08-20 23:40:02 +0000163 return utils.read_keyval(keyval_path)
jadmanskib591fba2008-09-10 16:19:22 +0000164 else:
165 return {}
166
167
mblighe79ebb02008-04-17 15:39:22 +0000168class patch(object):
jadmanski0afbb632008-06-06 21:10:57 +0000169 def __init__(self, spec, reference, hash):
170 self.spec = spec
171 self.reference = reference
172 self.hash = hash
mblighe79ebb02008-04-17 15:39:22 +0000173
174
175class iteration(object):
jadmanski0afbb632008-06-06 21:10:57 +0000176 def __init__(self, index, attr_keyval, perf_keyval):
177 self.index = index
178 self.attr_keyval = attr_keyval
179 self.perf_keyval = perf_keyval
jadmanskicc549172008-05-21 18:11:51 +0000180
181
jadmanski9978bdf2008-06-06 16:29:13 +0000182
jadmanski0afbb632008-06-06 21:10:57 +0000183 @staticmethod
184 def parse_line_into_dicts(line, attr_dict, perf_dict):
185 """Abstract method to parse a keyval line and insert it into
186 the appropriate dictionary.
187 attr_dict: generic iteration attributes
188 perf_dict: iteration performance results
189 """
190 raise NotImplementedError
jadmanskicc549172008-05-21 18:11:51 +0000191
192
jadmanski0afbb632008-06-06 21:10:57 +0000193 @classmethod
194 def load_from_keyval(cls, keyval_path):
195 """Load a list of iterations from an iteration keyval file.
196 Keyval data from separate iterations is separated by blank
197 lines. Makes use of the parse_line_into_dicts method to
198 actually parse the individual lines."""
199 if not os.path.exists(keyval_path):
200 return []
jadmanskicc549172008-05-21 18:11:51 +0000201
jadmanski0afbb632008-06-06 21:10:57 +0000202 iterations = []
203 index = 1
204 attr, perf = {}, {}
205 for line in file(keyval_path):
206 line = line.strip()
207 if line:
208 cls.parse_line_into_dicts(line, attr, perf)
209 else:
210 iterations.append(cls(index, attr, perf))
211 index += 1
212 attr, perf = {}, {}
213 if attr or perf:
214 iterations.append(cls(index, attr, perf))
215 return iterations