blob: b8b495e86f6d94b3ef5c768130c29e0102686d08 [file] [log] [blame]
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -08001#!/usr/bin/python
2
3# Copyright 2011 Google Inc. All Rights Reserved.
4
5import getpass
6import glob
7import hashlib
8import os
9import pickle
10import re
11from image_checksummer import ImageChecksummer
12from perf_processor import PerfProcessor
13from utils import command_executer
14from utils import logger
15from utils import utils
16
17SCRATCH_DIR = "/home/%s/cros_scratch" % getpass.getuser()
18RESULTS_FILE = "results.txt"
19AUTOTEST_TARBALL = "autotest.tbz2"
20PERF_RESULTS_FILE = "perf-results.txt"
21
22
23class Result(object):
Ahmad Sharif92ab7af2012-03-01 18:03:46 -080024 def __init__(self, out, err, retval, keyvals):
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -080025 self.out = out
26 self.err = err
27 self.retval = retval
Ahmad Sharif92ab7af2012-03-01 18:03:46 -080028 self.keyvals = keyvals
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -080029
30
31class CacheConditions(object):
32 # Cache hit only if the result file exists.
33 CACHE_FILE_EXISTS = 0
34
35 # Cache hit if the ip address of the cached result and the new run match.
36 REMOTES_MATCH = 1
37
38 # Cache hit if the image checksum of the cached result and the new run match.
39 CHECKSUMS_MATCH = 2
40
41 # Cache hit only if the cached result was successful
42 RUN_SUCCEEDED = 3
43
44 # Never a cache hit.
45 FALSE = 4
46
47
48class ResultsCache(object):
Ahmad Sharif92ab7af2012-03-01 18:03:46 -080049 CACHE_VERSION = 2
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -080050 def Init(self, chromeos_image, chromeos_root, autotest_name, iteration,
51 autotest_args, remote, board, cache_conditions,
52 logger_to_use):
53 self.chromeos_image = chromeos_image
54 self.chromeos_root = chromeos_root
55 self.autotest_name = autotest_name
56 self.iteration = iteration
57 self.autotest_args = autotest_args,
58 self.remote = remote
59 self.board = board
60 self.cache_conditions = cache_conditions
61 self._logger = logger_to_use
62 self._ce = command_executer.GetCommandExecuter(self._logger)
63
64 def _GetCacheDirForRead(self):
65 glob_path = self._FormCacheDir(self._GetCacheKeyList(True))
66 matching_dirs = glob.glob(glob_path)
67
68 if matching_dirs:
69 # Cache file found.
70 if len(matching_dirs) > 1:
71 self._logger.LogError("Multiple compatible cache files: %s." %
72 " ".join(matching_dirs))
73 return matching_dirs[0]
74 else:
75 return None
76
77 def _GetCacheDirForWrite(self):
78 return self._FormCacheDir(self._GetCacheKeyList(False))
79
80 def _FormCacheDir(self, list_of_strings):
81 cache_key = " ".join(list_of_strings)
82 cache_dir = self._ConvertToFilename(cache_key)
83 cache_path = os.path.join(SCRATCH_DIR, cache_dir)
84 return cache_path
85
86 def _GetCacheKeyList(self, read):
87 if read and CacheConditions.REMOTES_MATCH not in self.cache_conditions:
88 remote = "*"
89 else:
90 remote = self.remote
91 if read and CacheConditions.CHECKSUMS_MATCH not in self.cache_conditions:
92 checksum = "*"
93 else:
94 checksum = ImageChecksummer().Checksum(self.chromeos_image)
95 return (hashlib.md5(self.chromeos_image).hexdigest(),
96 self.autotest_name, str(self.iteration),
97 ",".join(self.autotest_args),
Ahmad Sharif92ab7af2012-03-01 18:03:46 -080098 checksum,
99 remote,
100 str(self.CACHE_VERSION))
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800101
102 def ReadResult(self):
103 if CacheConditions.FALSE in self.cache_conditions:
104 return None
105 cache_dir = self._GetCacheDirForRead()
106
107 if not cache_dir:
108 return None
109
110 try:
111 cache_file = os.path.join(cache_dir, RESULTS_FILE)
112
113 self._logger.LogOutput("Trying to read from cache file: %s" % cache_file)
114
115 with open(cache_file, "rb") as f:
Ahmad Sharif92ab7af2012-03-01 18:03:46 -0800116 result = pickle.load(f)
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800117
Ahmad Sharif92ab7af2012-03-01 18:03:46 -0800118 if (result.retval == 0 or
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800119 CacheConditions.RUN_SUCCEEDED not in self.cache_conditions):
Ahmad Sharif92ab7af2012-03-01 18:03:46 -0800120 return result
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800121
122 except Exception, e:
123 if CacheConditions.CACHE_FILE_EXISTS not in self.cache_conditions:
124 # Cache file not found but just return a failure.
Ahmad Sharif92ab7af2012-03-01 18:03:46 -0800125 return Result("", "", 1, {})
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800126 raise e
127
128 def StoreResult(self, result):
129 cache_dir = self._GetCacheDirForWrite()
130 cache_file = os.path.join(cache_dir, RESULTS_FILE)
131 command = "mkdir -p %s" % cache_dir
132 ret = self._ce.RunCommand(command)
133 assert ret == 0, "Couldn't create cache dir"
134 with open(cache_file, "wb") as f:
Ahmad Sharif92ab7af2012-03-01 18:03:46 -0800135 pickle.dump(result, f)
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800136
137 def StoreAutotestOutput(self, results_dir):
138 host_results_dir = os.path.join(self.chromeos_root, "chroot",
139 results_dir[1:])
140 tarball = os.path.join(self._GetCacheDirForWrite(), AUTOTEST_TARBALL)
141 command = ("cd %s && tar cjf %s ." % (host_results_dir, tarball))
142 ret = self._ce.RunCommand(command)
143 if ret:
144 raise Exception("Couldn't store autotest output directory.")
145
146 def ReadAutotestOutput(self, destination):
147 cache_dir = self._GetCacheDirForRead()
148 tarball = os.path.join(cache_dir, AUTOTEST_TARBALL)
149 if not os.path.exists(tarball):
150 raise Exception("Cached autotest tarball does not exist at '%s'." %
151 tarball)
152 command = ("cd %s && tar xjf %s ." % (destination, tarball))
153 ret = self._ce.RunCommand(command)
154 if ret:
155 raise Exception("Couldn't read autotest output directory.")
156
157 def StorePerfResults(self, perf):
158 perf_path = os.path.join(self._GetCacheDirForWrite(), PERF_RESULTS_FILE)
159 with open(perf_path, "wb") as f:
160 pickle.dump(perf.report, f)
161 pickle.dump(perf.output, f)
162
163 def ReadPerfResults(self):
164 cache_dir = self._GetCacheDirForRead()
165 perf_path = os.path.join(cache_dir, PERF_RESULTS_FILE)
166 with open(perf_path, "rb") as f:
167 report = pickle.load(f)
168 output = pickle.load(f)
169
170 return PerfProcessor.PerfResults(report, output)
171
172 def _ConvertToFilename(self, text):
173 ret = text
174 ret = re.sub("/", "__", ret)
175 ret = re.sub(" ", "_", ret)
176 ret = re.sub("=", "", ret)
177 ret = re.sub("\"", "", ret)
178 return ret
179
180
181class MockResultsCache(object):
182 def Init(self, *args):
183 pass
184
185 def ReadResult(self):
186 return Result("Results placed in /tmp/test", "", 0)
187
188 def StoreResult(self, result):
189 pass
190
191 def StoreAutotestOutput(self, results_dir):
192 pass
193
194 def ReadAutotestOutput(self, destination):
195 pass
196
197 def StorePerfResults(self, perf):
198 pass
199
200 def ReadPerfResults(self):
201 return PerfProcessor.PerfResults("", "")