| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/env python | |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 3 # Use of this source code is governed by a BSD-style license that can be | |
| 4 # found in the LICENSE file. | |
| 5 | |
| 6 import hashlib | |
| 7 import json | |
| 8 import logging | |
| 9 import os | |
| 10 import shutil | |
| 11 import subprocess | |
| 12 import sys | |
| 13 import tempfile | |
| 14 import unittest | |
| 15 | |
| 16 ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |
| 17 sys.path.insert(0, ROOT_DIR) | |
| 18 | |
| 19 VERBOSE = False | |
| 20 | |
| 21 | |
| 22 class CalledProcessError(subprocess.CalledProcessError): | |
| 23 """Makes 2.6 version act like 2.7""" | |
| 24 def __init__(self, returncode, cmd, output, stderr, cwd): | |
| 25 super(CalledProcessError, self).__init__(returncode, cmd) | |
| 26 self.output = output | |
| 27 self.stderr = stderr | |
| 28 self.cwd = cwd | |
| 29 | |
| 30 def __str__(self): | |
| 31 return super(CalledProcessError, self).__str__() + ( | |
| 32 '\n' | |
| 33 'cwd=%s\n%s\n%s\n%s') % ( | |
| 34 self.cwd, | |
| 35 self.output, | |
| 36 self.stderr, | |
| 37 ' '.join(self.cmd)) | |
| 38 | |
| 39 | |
| 40 def list_files_tree(directory): | |
| 41 """Returns the list of all the files in a tree.""" | |
| 42 actual = [] | |
| 43 for root, _dirs, files in os.walk(directory): | |
| 44 actual.extend(os.path.join(root, f)[len(directory)+1:] for f in files) | |
| 45 return sorted(actual) | |
| 46 | |
| 47 | |
| 48 def calc_sha1(filepath): | |
| 49 """Calculates the SHA-1 hash for a file.""" | |
| 50 return hashlib.sha1(open(filepath, 'rb').read()).hexdigest() | |
| 51 | |
| 52 | |
| 53 def write_content(filepath, content): | |
| 54 with open(filepath, 'wb') as f: | |
| 55 f.write(content) | |
| 56 | |
| 57 | |
| 58 def write_json(filepath, data): | |
| 59 with open(filepath, 'wb') as f: | |
| 60 json.dump(data, f, sort_keys=True, indent=2) | |
| 61 | |
| 62 | |
| 63 class RunTestFromArchive(unittest.TestCase): | |
| 64 def setUp(self): | |
| 65 self.tempdir = tempfile.mkdtemp(prefix='run_test_from_archive_smoke_test') | |
| 66 logging.debug(self.tempdir) | |
| 67 # The "source" hash table. | |
| 68 self.table = os.path.join(self.tempdir, 'table') | |
| 69 os.mkdir(self.table) | |
| 70 # The slave-side cache. | |
| 71 self.cache = os.path.join(self.tempdir, 'cache') | |
| 72 | |
| 73 self.data_dir = os.path.join(ROOT_DIR, 'tests', 'run_test_from_archive') | |
| 74 | |
| 75 def tearDown(self): | |
| 76 shutil.rmtree(self.tempdir) | |
| 77 | |
| 78 def _result_tree(self): | |
| 79 return list_files_tree(self.tempdir) | |
| 80 | |
| 81 @staticmethod | |
| 82 def _run(args): | |
| 83 cmd = [sys.executable, os.path.join(ROOT_DIR, 'run_test_from_archive.py')] | |
| 84 cmd.extend(args) | |
| 85 if VERBOSE: | |
| 86 cmd.extend(['-v'] * 2) | |
| 87 pipe = None | |
| 88 else: | |
| 89 pipe = subprocess.PIPE | |
| 90 logging.debug(' '.join(cmd)) | |
| 91 proc = subprocess.Popen( | |
| 92 cmd, stdout=pipe, stderr=pipe, universal_newlines=True) | |
| 93 out, err = proc.communicate() | |
| 94 return out, err, proc.returncode | |
| 95 | |
| 96 def _store_result(self, result_data): | |
| 97 """Stores a .results file in the hash table.""" | |
| 98 result_text = json.dumps(result_data, sort_keys=True, indent=2) | |
| 99 result_sha1 = hashlib.sha1(result_text).hexdigest() | |
| 100 write_content(os.path.join(self.table, result_sha1), result_text) | |
| 101 return result_sha1 | |
| 102 | |
| 103 def _store(self, filename): | |
| 104 """Stores a test data file in the table. | |
| 105 | |
| 106 Returns its sha-1 hash. | |
| 107 """ | |
| 108 filepath = os.path.join(self.data_dir, filename) | |
| 109 h = calc_sha1(filepath) | |
| 110 shutil.copyfile(filepath, os.path.join(self.table, h)) | |
| 111 return h | |
| 112 | |
| 113 def _generate_args(self, sha1_hash): | |
| 114 """Generates the standard arguments used with sha1_hash as the hash. | |
| 115 | |
| 116 Returns a list of the required arguments. | |
| 117 """ | |
| 118 return [ | |
| 119 '--hash', sha1_hash, | |
| 120 '--cache', self.cache, | |
| 121 '--remote', self.table, | |
| 122 ] | |
| 123 | |
| 124 def test_result(self): | |
| 125 # Loads an arbitrary manifest on the file system. | |
| 126 manifest = os.path.join(self.data_dir, 'gtest_fake.results') | |
| 127 expected = [ | |
| 128 'state.json', | |
| 129 self._store('gtest_fake.py'), | |
| 130 calc_sha1(manifest), | |
| 131 ] | |
| 132 args = [ | |
| 133 '--manifest', manifest, | |
| 134 '--cache', self.cache, | |
| 135 '--remote', self.table, | |
| 136 ] | |
| 137 out, err, returncode = self._run(args) | |
| 138 if not VERBOSE: | |
| 139 self.assertEquals('', err) | |
| 140 self.assertEquals(1070, len(out), out) | |
| 141 self.assertEquals(6, returncode) | |
| 142 actual = list_files_tree(self.cache) | |
| 143 self.assertEquals(sorted(expected), actual) | |
| 144 | |
| 145 def test_hash(self): | |
| 146 # Loads the manifest from the store as a hash. | |
| 147 result_sha1 = self._store('gtest_fake.results') | |
| 148 expected = [ | |
| 149 'state.json', | |
| 150 self._store('gtest_fake.py'), | |
| 151 result_sha1, | |
| 152 ] | |
| 153 args = [ | |
| 154 '--hash', result_sha1, | |
| 155 '--cache', self.cache, | |
| 156 '--remote', self.table, | |
| 157 ] | |
| 158 out, err, returncode = self._run(args) | |
| 159 if not VERBOSE: | |
| 160 self.assertEquals('', err) | |
| 161 self.assertEquals(1070, len(out), out) | |
| 162 self.assertEquals(6, returncode) | |
| 163 actual = list_files_tree(self.cache) | |
| 164 self.assertEquals(sorted(expected), actual) | |
| 165 | |
| 166 def test_fail_empty_manifest(self): | |
| 167 result_sha1 = self._store_result({}) | |
| 168 expected = [ | |
| 169 'state.json', | |
| 170 result_sha1, | |
| 171 ] | |
| 172 out, err, returncode = self._run(self._generate_args(result_sha1)) | |
| 173 if not VERBOSE: | |
| 174 self.assertEquals('', out) | |
| 175 self.assertEquals('No command to run\n', err) | |
| 176 self.assertEquals(1, returncode) | |
| 177 actual = list_files_tree(self.cache) | |
| 178 self.assertEquals(sorted(expected), actual) | |
| 179 | |
| 180 def test_includes(self): | |
| 181 # Loads a manifest that includes another one. | |
| 182 | |
| 183 # References manifest1.results and gtest_fake.results. Maps file3.txt as | |
| 184 # file2.txt. | |
| 185 result_sha1 = self._store('check_files.results') | |
| 186 expected = [ | |
| 187 'state.json', | |
| 188 self._store('check_files.py'), | |
| 189 self._store('gtest_fake.py'), | |
| 190 self._store('gtest_fake.results'), | |
| 191 self._store('file1.txt'), | |
| 192 self._store('file3.txt'), | |
| 193 # Maps file1.txt. | |
| 194 self._store('manifest1.results'), | |
| 195 # References manifest1.results. Maps file2.txt but it is overriden. | |
| 196 self._store('manifest2.results'), | |
| 197 result_sha1, | |
| 198 ] | |
| 199 out, err, returncode = self._run(self._generate_args(result_sha1)) | |
| 200 if not VERBOSE: | |
| 201 self.assertEquals('', err) | |
| 202 self.assertEquals('Success\n', out) | |
| 203 self.assertEquals(0, returncode) | |
| 204 actual = list_files_tree(self.cache) | |
| 205 self.assertEquals(sorted(expected), actual) | |
| 206 | |
| 207 def test_link_all_hash_instances(self): | |
| 208 # Load a manifest file with the same file (same sha-1 hash), listed under | |
| 209 # two different names and ensure both are created. | |
| 210 result_sha1 = self._store('repeated_files.results') | |
| 211 expected = [ | |
| 212 'state.json', | |
| 213 result_sha1, | |
| 214 self._store('file1.txt'), | |
| 215 self._store('repeated_files.py') | |
| 216 ] | |
| 217 | |
| 218 out, err, returncode = self._run(self._generate_args(result_sha1)) | |
| 219 if not VERBOSE: | |
| 220 self.assertEquals('', err) | |
| 221 self.assertEquals('Success\n', out) | |
| 222 self.assertEquals(0, returncode) | |
| 223 actual = list_files_tree(self.cache) | |
| 224 self.assertEquals(sorted(expected), actual) | |
| 225 | |
| 226 | |
| 227 if __name__ == '__main__': | |
| 228 VERBOSE = '-v' in sys.argv | |
| 229 logging.basicConfig(level=logging.DEBUG if VERBOSE else logging.ERROR) | |
| 230 unittest.main() | |
| OLD | NEW |