Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(355)

Side by Side Diff: infra/services/gnumbd/test/inner_loop_test.py

Issue 355153002: Refactor infra git libs and testing. (Closed) Base URL: https://chromium.googlesource.com/infra/infra@fake_testing_support
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import collections 5 import collections
6 import glob
6 import json 7 import json
7 import logging 8 import logging
8 import os 9 import os
10 import shutil
9 import sys 11 import sys
10 import tempfile 12 import tempfile
11 13
12 from cStringIO import StringIO 14 from cStringIO import StringIO
13 15
14 from infra.services.gnumbd import inner_loop as gnumbd 16 from infra.services.gnumbd import inner_loop
15 17
16 from infra.services.gnumbd.support import config_ref, data, git 18 from infra.libs import git2
19 from infra.libs.git2 import config_ref
20 from infra.libs.git2 import data
17 21
18 from infra.services.gnumbd.test import gnumbd_smoketests 22 from infra.services.gnumbd.test import inner_loop_test_definitions
19 23
20 from infra.ext import testing_support # pylint: disable=W0611 24 from infra.ext import testing_support # pylint: disable=W0611
21 from testing_support import expect_tests # pylint: disable=F0401 25 from testing_support import expect_tests # pylint: disable=F0401
22 26
23 BASE_PATH = os.path.dirname(os.path.abspath(__file__)) 27 BASE_PATH = os.path.dirname(os.path.abspath(__file__))
24 28
25 29
26 # TODO(iannucci): Make these first class data library objects 30 # TODO(iannucci): Make these first class data library objects
27 class GitEntry(object): 31 class GitEntry(object):
28 typ = None 32 typ = None
(...skipping 29 matching lines...) Expand all
58 self.entries = entries 62 self.entries = entries
59 63
60 def intern(self, repo): 64 def intern(self, repo):
61 with tempfile.TemporaryFile() as tf: 65 with tempfile.TemporaryFile() as tf:
62 for path, entry in self.entries.iteritems(): 66 for path, entry in self.entries.iteritems():
63 tf.write('%s %s %s\t%s' % 67 tf.write('%s %s %s\t%s' %
64 (entry.mode, entry.typ, entry.intern(repo), path)) 68 (entry.mode, entry.typ, entry.intern(repo), path))
65 tf.seek(0) 69 tf.seek(0)
66 return repo.run('mktree', '-z', stdin=tf).strip() 70 return repo.run('mktree', '-z', stdin=tf).strip()
67 71
68 class TestRef(git.Ref): 72 class TestRef(git2.Ref):
69 def synthesize_commit(self, message, number=None, tree=None, svn=False, 73 def synthesize_commit(self, message, number=None, tree=None, svn=False,
70 footers=None): 74 footers=None):
71 footers = footers or collections.OrderedDict() 75 footers = footers or collections.OrderedDict()
72 if number is not None: 76 if number is not None:
73 if svn: 77 if svn:
74 footers[gnumbd.GIT_SVN_ID] = [ 78 footers[inner_loop.GIT_SVN_ID] = [
75 'svn://repo/path@%s 0039d316-1c4b-4281-b951-d872f2087c98' % number] 79 'svn://repo/path@%s 0039d316-1c4b-4281-b951-d872f2087c98' % number]
76 else: 80 else:
77 footers[gnumbd.COMMIT_POSITION] = [ 81 footers[inner_loop.COMMIT_POSITION] = [
78 gnumbd.FMT_COMMIT_POSITION(self, number)] 82 inner_loop.FMT_COMMIT_POSITION(self, number)]
79 83
80 commit = self.repo.synthesize_commit(self.commit, message, footers=footers, 84 commit = self.repo.synthesize_commit(self.commit, message, footers=footers,
81 tree=tree) 85 tree=tree)
82 self.update_to(commit) 86 self.update_to(commit)
83 return commit 87 return commit
84 88
85 89
86 class TestClock(object): 90 class TestClock(object):
87 def __init__(self): 91 def __init__(self):
88 self._time = 1402589336 92 self._time = 1402589336
89 93
90 def time(self): 94 def time(self):
91 self._time += 10 95 self._time += 10
92 return self._time 96 return self._time
93 97
94 98
95 class TestConfigRef(config_ref.ConfigRef): 99 class TestConfigRef(config_ref.ConfigRef):
96 def update(self, **values): 100 def update(self, **values):
97 new_config = self.current 101 new_config = self.current
98 new_config.update(values) 102 new_config.update(values)
99 self.ref.synthesize_commit( 103 self.ref.synthesize_commit(
100 'update(%r)' % values.keys(), 104 'update(%r)' % values.keys(),
101 tree=GitTree({'config.json': GitFile(json.dumps(new_config))})) 105 tree=GitTree({'config.json': GitFile(json.dumps(new_config))}))
102 106
103 107
104 class TestRepo(git.Repo): 108 class TestRepo(git2.Repo):
105 def __init__(self, short_name, tmpdir, clock, mirror_of=None): 109 def __init__(self, short_name, tmpdir, clock, mirror_of=None):
106 super(TestRepo, self).__init__(mirror_of or 'local test repo') 110 super(TestRepo, self).__init__(mirror_of or 'local test repo')
107 self._short_name = short_name 111 self._short_name = short_name
108 self.repos_dir = tmpdir 112 self.repos_dir = tmpdir
109 113
110 if mirror_of is None: 114 if mirror_of is None:
111 self._repo_path = tempfile.mkdtemp(dir=self.repos_dir, suffix='.git') 115 self._repo_path = tempfile.mkdtemp(dir=self.repos_dir, suffix='.git')
112 self.run('init', '--bare') 116 self.run('init', '--bare')
113 117
114 self._clock = clock 118 self._clock = clock
115 119
116 # pylint: disable=W0212 120 # pylint: disable=W0212
117 repo_path = property(lambda self: self._repo_path) 121 repo_path = property(lambda self: self._repo_path)
118 122
119 def __getitem__(self, refstr): 123 def __getitem__(self, refstr):
120 return TestRef(self, refstr) 124 return TestRef(self, refstr)
121 125
122 def synthesize_commit(self, parent, message, tree=None, footers=None): 126 def synthesize_commit(self, parent, message, tree=None, footers=None):
123 tree = tree or GitTree({'file': GitFile('contents')}) 127 tree = tree or GitTree({'file': GitFile('contents')})
124 tree = tree.intern(self) if isinstance(tree, GitTree) else tree 128 tree = tree.intern(self) if isinstance(tree, GitTree) else tree
125 assert isinstance(tree, str) 129 assert isinstance(tree, str)
126 130
127 parents = [parent.hsh] if parent is not git.INVALID else [] 131 parents = [parent.hsh] if parent is not git2.INVALID else []
128 132
129 timestamp = data.CommitTimestamp(self._clock.time(), '+', 8, 0) 133 timestamp = data.CommitTimestamp(self._clock.time(), '+', 8, 0)
130 user = data.CommitUser('Test User', 'test_user@example.com', timestamp) 134 user = data.CommitUser('Test User', 'test_user@example.com', timestamp)
131 135
132 return self.get_commit(self.intern(data.CommitData( 136 return self.get_commit(self.intern(data.CommitData(
133 tree, parents, user, user, (), message.splitlines(), 137 tree, parents, user, user, (), message.splitlines(),
134 data.CommitData.merge_lines([], footers or {}) 138 data.CommitData.merge_lines([], footers or {})
135 ), 'commit')) 139 ), 'commit'))
136 140
137 def snap(self, include_committer=False, include_config=False): 141 def snap(self, include_committer=False, include_config=False):
138 ret = {} 142 ret = {}
139 if include_committer: 143 if include_committer:
140 fmt = '%H%x00committer %cn <%ce> %ci%n%n%B%x00%x00' 144 fmt = '%H%x00committer %cn <%ce> %ci%n%n%B%x00%x00'
141 else: 145 else:
142 fmt = '%H%x00%B%x00%x00' 146 fmt = '%H%x00%B%x00%x00'
143 for ref in (r.ref for r in self.refglob('*')): 147 for ref in (r.ref for r in self.refglob('*')):
144 if ref == gnumbd.DEFAULT_CONFIG_REF and not include_config: 148 if ref == inner_loop.DEFAULT_CONFIG_REF and not include_config:
145 continue 149 continue
146 log = self.run('log', ref, '--format=%s' % fmt) 150 log = self.run('log', ref, '--format=%s' % fmt)
147 ret[ref] = collections.OrderedDict( 151 ret[ref] = collections.OrderedDict(
148 (commit, message.splitlines()) 152 (commit, message.splitlines())
149 for commit, message in ( 153 for commit, message in (
150 r.split('\0') for r in log.split('\0\0\n') if r) 154 r.split('\0') for r in log.split('\0\0\n') if r)
151 ) 155 )
152 return ret 156 return ret
153 157
154 def __repr__(self): 158 def __repr__(self):
155 return 'TestRepo(%r)' % self._short_name 159 return 'TestRepo(%r)' % self._short_name
156 160
157 161
158 def RunTest(tmpdir, test_name): 162 def RunTest(tmpdir, test_name):
159 ret = [] 163 ret = []
160 clock = TestClock() 164 clock = TestClock()
161 origin = TestRepo('origin', tmpdir, clock) 165 origin = TestRepo('origin', tmpdir, clock)
162 local = TestRepo('local', tmpdir, clock, origin.repo_path) 166 local = TestRepo('local', tmpdir, clock, origin.repo_path)
163 167
164 cref = TestConfigRef(origin[gnumbd.DEFAULT_CONFIG_REF]) 168 cref = TestConfigRef(origin[inner_loop.DEFAULT_CONFIG_REF])
165 cref.update(enabled_refglobs=['refs/heads/*'], interval=0) 169 cref.update(enabled_refglobs=['refs/heads/*'], interval=0)
166 170
167 def checkpoint(message, include_committer=False, include_config=False): 171 def checkpoint(message, include_committer=False, include_config=False):
168 ret.append([message, {'origin': origin.snap(include_committer, 172 ret.append([message, {'origin': origin.snap(include_committer,
169 include_config)}]) 173 include_config)}])
170 174
171 def run(include_log=True): 175 def run(include_log=True):
172 stdout = sys.stdout 176 stdout = sys.stdout
173 stderr = sys.stderr 177 stderr = sys.stderr
174 178
175 if include_log: 179 if include_log:
176 logout = StringIO() 180 logout = StringIO()
177 root_logger = logging.getLogger() 181 root_logger = logging.getLogger()
178 log_level = root_logger.getEffectiveLevel() 182 log_level = root_logger.getEffectiveLevel()
179 shandler = logging.StreamHandler(logout) 183 shandler = logging.StreamHandler(logout)
180 shandler.setFormatter( 184 shandler.setFormatter(
181 logging.Formatter('%(levelname)s: %(message)s')) 185 logging.Formatter('%(levelname)s: %(message)s'))
182 root_logger.addHandler(shandler) 186 root_logger.addHandler(shandler)
183 root_logger.setLevel(logging.INFO) 187 root_logger.setLevel(logging.INFO)
184 188
185 try: 189 try:
186 sys.stderr = sys.stdout = open(os.devnull, 'w') 190 sys.stderr = sys.stdout = open(os.devnull, 'w')
187 local.reify() 191 local.reify()
188 gnumbd.inner_loop(local, cref, clock) 192 inner_loop.inner_loop(local, cref, clock)
189 except Exception: # pragma: no cover 193 except Exception: # pragma: no cover
190 import traceback 194 import traceback
191 ret.append(traceback.format_exc().splitlines()) 195 ret.append(traceback.format_exc().splitlines())
192 finally: 196 finally:
193 sys.stdout = stdout 197 sys.stdout = stdout
194 sys.stderr = stderr 198 sys.stderr = stderr
195 199
196 if include_log: 200 if include_log:
197 root_logger.removeHandler(shandler) 201 root_logger.removeHandler(shandler)
198 root_logger.setLevel(log_level) 202 root_logger.setLevel(log_level)
199 ret.append({'log output': logout.getvalue().splitlines()}) 203 ret.append({'log output': logout.getvalue().splitlines()})
200 204
201 gnumbd_smoketests.GNUMBD_TESTS[test_name]( 205 inner_loop_test_definitions.GNUMBD_TESTS[test_name](
202 origin, local, cref, run, checkpoint) 206 origin, local, cref, run, checkpoint)
203 207
204 return expect_tests.Result(ret) 208 return expect_tests.Result(ret)
205 209
206 210
207 def GenTests(tmpdir): 211 @expect_tests.generator
208 for test_name, test in gnumbd_smoketests.GNUMBD_TESTS.iteritems(): 212 def GenTests():
213 suffix = '.gnumbd_inner_loop'
214 tmpdir = tempfile.mkdtemp(suffix)
215 for p in glob.glob(os.path.join(os.path.dirname(tmpdir), '*'+suffix)):
216 if p != tmpdir: # pragma: no cover
217 shutil.rmtree(p)
218
219 yield expect_tests.Cleanup(expect_tests.FuncCall(shutil.rmtree, tmpdir))
220
221 for test_name, test in inner_loop_test_definitions.GNUMBD_TESTS.iteritems():
209 yield expect_tests.Test( 222 yield expect_tests.Test(
210 __package__ + '.' + test_name, 223 __package__ + '.' + test_name,
211 expect_tests.FuncCall(RunTest, tmpdir, test_name), 224 expect_tests.FuncCall(RunTest, tmpdir, test_name),
212 os.path.join(BASE_PATH, 'gnumbd_smoketests.expected'), 225 expect_base=test_name, ext='yaml', break_funcs=[test],
213 test_name, 'yaml', break_funcs=[test]) 226 covers=(
227 expect_tests.Test.covers_obj(RunTest) +
228 expect_tests.Test.covers_obj(inner_loop_test_definitions)
229 ))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698