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

Side by Side Diff: unittests/autoroll_test.py

Issue 2756503003: [autoroll] make autoroller propagate changes to recipes.py. (Closed)
Patch Set: rebase Created 3 years, 9 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
« no previous file with comments | « recipe_engine/autoroll.py ('k') | unittests/repo_test_util.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2016 The LUCI Authors. All rights reserved. 2 # Copyright 2016 The LUCI Authors. All rights reserved.
3 # Use of this source code is governed under the Apache License, Version 2.0 3 # Use of this source code is governed under the Apache License, Version 2.0
4 # that can be found in the LICENSE file. 4 # that can be found in the LICENSE file.
5 5
6 import json 6 import json
7 import os 7 import os
8 import subprocess 8 import subprocess
9 import sys 9 import sys
10 import unittest 10 import unittest
11 11
12 import repo_test_util 12 import repo_test_util
13 13
14 14
15 class TestAutoroll(repo_test_util.RepoTest): 15 class TestAutoroll(repo_test_util.RepoTest):
16 def run_roll(self, repo, *args): 16 def run_roll(self, repo, *args):
17 """Runs the autoroll command and returns JSON. 17 """Runs the autoroll command and returns JSON.
18 Does not commit the resulting roll. 18 Does not commit the resulting roll.
19 """ 19 """
20 with repo_test_util.in_directory(repo['root']), \ 20 with repo_test_util.in_directory(repo['root']), \
21 repo_test_util.temporary_file() as tempfile_path: 21 repo_test_util.temporary_file() as tempfile_path:
22 subprocess.check_output([ 22 subprocess.check_output([
23 sys.executable, self._recipe_tool, 23 sys.executable, self._recipe_tool,
24 '--package', os.path.join( 24 '--package', os.path.join(
25 repo['root'], 'infra', 'config', 'recipes.cfg'), 25 repo['root'], 'infra', 'config', 'recipes.cfg'),
26 '--use-bootstrap', 26 '--use-bootstrap',
27 'autoroll', 27 'autoroll',
28 '--output-json', tempfile_path 28 '--output-json', tempfile_path
29 ] + list(args), stderr=subprocess.STDOUT) 29 ] + list(args) , stderr=subprocess.STDOUT)
30 with open(tempfile_path) as f: 30 with open(tempfile_path) as f:
31 return json.load(f) 31 return json.load(f)
32 32
33 def test_empty(self): 33 def test_empty(self):
34 """Tests the scenario where there are no roll candidates. 34 """Tests the scenario where there are no roll candidates.
35 """ 35 """
36 repos = self.repo_setup({ 36 repos = self.repo_setup({
37 'a': [], 37 'a': [],
38 }) 38 })
39 39
40 roll_result = self.run_roll(repos['a']) 40 roll_result = self.run_roll(repos['a'])
41 self.assertFalse(roll_result['success']) 41 self.assertFalse(roll_result['success'])
42 self.assertEquals([], roll_result['roll_details']) 42 self.assertEquals([], roll_result['roll_details'])
43 self.assertEquals([], roll_result['rejected_candidates_details']) 43 self.assertEquals([], roll_result['rejected_candidates_details'])
44 44
45 def test_bogus_recipes_py(self):
46 repos = self.repo_setup({
47 'a': [],
48 'b': ['a'],
49 })
50 self.get_package_spec(repos['b'])
51
52 # Create a new commit in the A repo.
53 self.commit_in_repo(repos['a'], message='c1')
54
55 # goof up recipes.py in B repo.
56 with open(os.path.join(repos['b']['root'], 'recipes.py'), 'wb') as f:
57 print >> f, "Hey! This isn't even a python script."
58 self.commit_in_repo(repos['b'], message='goof it up!')
59
60 with self.assertRaises(subprocess.CalledProcessError) as ex:
61 self.run_roll(repos['b'])
62 self.assertIn('unable to find configuration section', ex.exception.output)
63
64
45 def test_trivial(self): 65 def test_trivial(self):
46 """Tests the simplest trivial (i.e. no expectation changes) roll scenario. 66 """Tests the simplest trivial (i.e. no expectation changes) roll scenario.
47 """ 67 """
48 repos = self.repo_setup({ 68 repos = self.repo_setup({
49 'a': [], 69 'a': [],
50 'b': ['a'], 70 'b': ['a'],
51 }) 71 })
52 b_package_spec = self.get_package_spec(repos['b']) 72 b_package_spec = self.get_package_spec(repos['b'])
53 73
54 # Create a new commit in the A repo. 74 # Create a new commit in the A repo.
(...skipping 28 matching lines...) Expand all
83 def test_nontrivial(self): 103 def test_nontrivial(self):
84 """Tests the simplest nontrivial (i.e. expectation changes) roll scenario. 104 """Tests the simplest nontrivial (i.e. expectation changes) roll scenario.
85 """ 105 """
86 repos = self.repo_setup({ 106 repos = self.repo_setup({
87 'a': [], 107 'a': [],
88 'b': ['a'], 108 'b': ['a'],
89 }) 109 })
90 b_package_spec = self.get_package_spec(repos['b']) 110 b_package_spec = self.get_package_spec(repos['b'])
91 111
92 # Set up a recipe in repo B depending on a module in repo A. 112 # Set up a recipe in repo B depending on a module in repo A.
93 a_c1 = self.update_recipe_module(repos['a'], 'a_module', {'foo': ['bar']}) 113 self.update_recipe_module(repos['a'], 'a_module', {'foo': ['bar']})
94 roll_result = self.run_roll(repos['b']) 114 roll_result = self.run_roll(repos['b'])
95 self.assertTrue(roll_result['success']) 115 self.assertTrue(roll_result['success'])
96 self.assertTrue(roll_result['trivial']) 116 self.assertTrue(roll_result['trivial'])
97 b_c1 = self.update_recipe( 117 self.update_recipe(
98 repos['b'], 'b_recipe', ['a/a_module'], [('a_module', 'foo')]) 118 repos['b'], 'b_recipe', ['a/a_module'], [('a_module', 'foo')])
99 119
100 # Change API of the recipe module in a way that's compatible, 120 # Change API of the recipe module in a way that's compatible,
101 # but changes expectations. 121 # but changes expectations.
102 a_c2 = self.update_recipe_module(repos['a'], 'a_module', {'foo': ['baz']}) 122 a_c2 = self.update_recipe_module(repos['a'], 'a_module', {'foo': ['baz']})
103 123
104 roll_result = self.run_roll(repos['b']) 124 roll_result = self.run_roll(repos['b'])
105 self.assertTrue(roll_result['success']) 125 self.assertTrue(roll_result['success'])
106 self.assertFalse(roll_result['trivial']) 126 self.assertFalse(roll_result['trivial'])
107 127
(...skipping 25 matching lines...) Expand all
133 def test_failure(self): 153 def test_failure(self):
134 """Tests the simplest scenario where an automated roll is not possible 154 """Tests the simplest scenario where an automated roll is not possible
135 because of incompatible API changes. 155 because of incompatible API changes.
136 """ 156 """
137 repos = self.repo_setup({ 157 repos = self.repo_setup({
138 'a': [], 158 'a': [],
139 'b': ['a'], 159 'b': ['a'],
140 }) 160 })
141 161
142 # Set up a recipe in repo B depending on a module in repo A. 162 # Set up a recipe in repo B depending on a module in repo A.
143 a_c1 = self.update_recipe_module(repos['a'], 'a_module', {'foo': ['bar']}) 163 self.update_recipe_module(repos['a'], 'a_module', {'foo': ['bar']})
144 roll_result = self.run_roll(repos['b']) 164 roll_result = self.run_roll(repos['b'])
145 self.assertTrue(roll_result['success']) 165 self.assertTrue(roll_result['success'])
146 self.assertTrue(roll_result['trivial']) 166 self.assertTrue(roll_result['trivial'])
147 b_c1 = self.update_recipe( 167 self.update_recipe(
148 repos['b'], 'b_recipe', ['a/a_module'], [('a_module', 'foo')]) 168 repos['b'], 'b_recipe', ['a/a_module'], [('a_module', 'foo')])
149 169
150 # Change API of the recipe module in an incompatible way. 170 # Change API of the recipe module in an incompatible way.
151 a_c2 = self.update_recipe_module(repos['a'], 'a_module', {'baz': ['baz']}) 171 self.update_recipe_module(repos['a'], 'a_module', {'baz': ['baz']})
152 172
153 roll_result = self.run_roll(repos['b']) 173 roll_result = self.run_roll(repos['b'])
154 self.assertFalse(roll_result['success']) 174 self.assertFalse(roll_result['success'])
155 175
156 def test_jump_over_failure(self): 176 def test_jump_over_failure(self):
157 """Tests whether the roller considers pulling more commits to make 177 """Tests whether the roller considers pulling more commits to make
158 the roll succeed, when earlier ones have incompatible API changes 178 the roll succeed, when earlier ones have incompatible API changes
159 fixed later. 179 fixed later.
160 """ 180 """
161 repos = self.repo_setup({ 181 repos = self.repo_setup({
162 'a': [], 182 'a': [],
163 'b': ['a'], 183 'b': ['a'],
164 }) 184 })
165 b_package_spec = self.get_package_spec(repos['b']) 185 b_package_spec = self.get_package_spec(repos['b'])
166 186
167 # Set up a recipe in repo B depending on a module in repo A. 187 # Set up a recipe in repo B depending on a module in repo A.
168 a_c1 = self.update_recipe_module(repos['a'], 'a_module', {'foo': ['bar']}) 188 self.update_recipe_module(repos['a'], 'a_module', {'foo': ['bar']})
169 roll_result = self.run_roll(repos['b']) 189 roll_result = self.run_roll(repos['b'])
170 self.assertTrue(roll_result['success']) 190 self.assertTrue(roll_result['success'])
171 self.assertTrue(roll_result['trivial']) 191 self.assertTrue(roll_result['trivial'])
172 b_c1 = self.update_recipe( 192 self.update_recipe(
173 repos['b'], 'b_recipe', ['a/a_module'], [('a_module', 'foo')]) 193 repos['b'], 'b_recipe', ['a/a_module'], [('a_module', 'foo')])
174 194
175 # Change API of the recipe module in an incompatible way. 195 # Change API of the recipe module in an incompatible way.
176 a_c2 = self.update_recipe_module(repos['a'], 'a_module', {'baz': ['baz']}) 196 a_c2 = self.update_recipe_module(repos['a'], 'a_module', {'baz': ['baz']})
177 197
178 # Restore compatibility, but change expectations. 198 # Restore compatibility, but change expectations.
179 a_c3 = self.update_recipe_module(repos['a'], 'a_module', {'foo': ['baz']}) 199 a_c3 = self.update_recipe_module(repos['a'], 'a_module', {'foo': ['baz']})
180 200
181 roll_result = self.run_roll(repos['b']) 201 roll_result = self.run_roll(repos['b'])
182 self.assertTrue(roll_result['success']) 202 self.assertTrue(roll_result['success'])
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 """Test that with several nontrivial rolls possible, the minimal one 237 """Test that with several nontrivial rolls possible, the minimal one
218 is picked. 238 is picked.
219 """ 239 """
220 repos = self.repo_setup({ 240 repos = self.repo_setup({
221 'a': [], 241 'a': [],
222 'b': ['a'], 242 'b': ['a'],
223 }) 243 })
224 b_package_spec = self.get_package_spec(repos['b']) 244 b_package_spec = self.get_package_spec(repos['b'])
225 245
226 # Set up a recipe in repo B depending on a module in repo A. 246 # Set up a recipe in repo B depending on a module in repo A.
227 a_c1 = self.update_recipe_module(repos['a'], 'a_module', {'foo': ['bar']}) 247 self.update_recipe_module(repos['a'], 'a_module', {'foo': ['bar']})
228 roll_result = self.run_roll(repos['b']) 248 roll_result = self.run_roll(repos['b'])
229 self.assertTrue(roll_result['success']) 249 self.assertTrue(roll_result['success'])
230 self.assertTrue(roll_result['trivial']) 250 self.assertTrue(roll_result['trivial'])
231 b_c1 = self.update_recipe( 251 self.update_recipe(
232 repos['b'], 'b_recipe', ['a/a_module'], [('a_module', 'foo')]) 252 repos['b'], 'b_recipe', ['a/a_module'], [('a_module', 'foo')])
233 253
234 # Change API of the recipe module in an incompatible way. 254 # Change API of the recipe module in an incompatible way.
235 a_c2 = self.update_recipe_module(repos['a'], 'a_module', {'baz': ['baz']}) 255 a_c2 = self.update_recipe_module(repos['a'], 'a_module', {'baz': ['baz']})
236 256
237 # Restore compatibility, but change expectations. 257 # Restore compatibility, but change expectations.
238 a_c3 = self.update_recipe_module(repos['a'], 'a_module', {'foo': ['baz']}) 258 a_c3 = self.update_recipe_module(repos['a'], 'a_module', {'foo': ['baz']})
239 259
240 # Create another change that would result in a nontrivial roll, 260 # Create another change that would result in a nontrivial roll,
241 # which should not be picked - nontrivial rolls should be minimal. 261 # which should not be picked - nontrivial rolls should be minimal.
242 a_c4 = self.update_recipe_module(repos['a'], 'a_module', {'foo': ['bam']}) 262 self.update_recipe_module(repos['a'], 'a_module', {'foo': ['bam']})
243 263
244 roll_result = self.run_roll(repos['b']) 264 roll_result = self.run_roll(repos['b'])
245 self.assertTrue(roll_result['success']) 265 self.assertTrue(roll_result['success'])
246 self.assertFalse(roll_result['trivial']) 266 self.assertFalse(roll_result['trivial'])
247 267
248 expected_picked_roll = { 268 expected_picked_roll = {
249 'commit_infos': { 269 'commit_infos': {
250 'a': [ 270 'a': [
251 { 271 {
252 'author': a_c2['author_email'], 272 'author': a_c2['author_email'],
(...skipping 28 matching lines...) Expand all
281 This helps avoid noise with several rolls where one is sufficient, 301 This helps avoid noise with several rolls where one is sufficient,
282 with no expectation changes. 302 with no expectation changes.
283 """ 303 """
284 repos = self.repo_setup({ 304 repos = self.repo_setup({
285 'a': [], 305 'a': [],
286 'b': ['a'], 306 'b': ['a'],
287 }) 307 })
288 b_package_spec = self.get_package_spec(repos['b']) 308 b_package_spec = self.get_package_spec(repos['b'])
289 309
290 # Set up a recipe in repo B depending on a module in repo A. 310 # Set up a recipe in repo B depending on a module in repo A.
291 a_c1 = self.update_recipe_module(repos['a'], 'a_module', {'foo': ['bar']}) 311 self.update_recipe_module(repos['a'], 'a_module', {'foo': ['bar']})
292 roll_result = self.run_roll(repos['b']) 312 roll_result = self.run_roll(repos['b'])
293 self.assertTrue(roll_result['success']) 313 self.assertTrue(roll_result['success'])
294 self.assertTrue(roll_result['trivial']) 314 self.assertTrue(roll_result['trivial'])
295 b_c1 = self.update_recipe( 315 self.update_recipe(
296 repos['b'], 'b_recipe', ['a/a_module'], [('a_module', 'foo')]) 316 repos['b'], 'b_recipe', ['a/a_module'], [('a_module', 'foo')])
297 317
298 # Change API of the recipe module in an incompatible way. 318 # Change API of the recipe module in an incompatible way.
299 a_c2 = self.update_recipe_module(repos['a'], 'a_module', {'baz': ['baz']}) 319 a_c2 = self.update_recipe_module(repos['a'], 'a_module', {'baz': ['baz']})
300 320
301 # Restore compatibility, but change expectations. 321 # Restore compatibility, but change expectations.
302 a_c3 = self.update_recipe_module(repos['a'], 'a_module', {'foo': ['baz']}) 322 a_c3 = self.update_recipe_module(repos['a'], 'a_module', {'foo': ['baz']})
303 323
304 # Create another change that would result in a nontrivial roll, 324 # Create another change that would result in a nontrivial roll,
305 # which should not be picked - nontrivial rolls should be minimal. 325 # which should not be picked - nontrivial rolls should be minimal.
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 """ 380 """
361 repos = self.repo_setup({ 381 repos = self.repo_setup({
362 'a': [], 382 'a': [],
363 'b': ['a'], 383 'b': ['a'],
364 'c': ['b', 'a'], 384 'c': ['b', 'a'],
365 }) 385 })
366 b_package_spec = self.get_package_spec(repos['b']) 386 b_package_spec = self.get_package_spec(repos['b'])
367 c_package_spec = self.get_package_spec(repos['c']) 387 c_package_spec = self.get_package_spec(repos['c'])
368 388
369 # Set up a recipe in repo C depending on a module in repo B. 389 # Set up a recipe in repo C depending on a module in repo B.
370 b_c1 = self.update_recipe_module(repos['b'], 'b_module', {'foo': ['bar']}) 390 self.update_recipe_module(repos['b'], 'b_module', {'foo': ['bar']})
371 roll_result = self.run_roll(repos['c']) 391 roll_result = self.run_roll(repos['c'])
372 self.assertTrue(roll_result['success']) 392 self.assertTrue(roll_result['success'])
373 self.assertTrue(roll_result['trivial']) 393 self.assertTrue(roll_result['trivial'])
374 c_c1 = self.update_recipe( 394 self.update_recipe(
375 repos['c'], 'c_recipe', ['b/b_module'], [('b_module', 'foo')]) 395 repos['c'], 'c_recipe', ['b/b_module'], [('b_module', 'foo')])
376 396
377 # Create a new commit in the A repo and roll it into B. 397 # Create a new commit in the A repo and roll it into B.
378 a_c1 = self.commit_in_repo(repos['a'], message='c1') 398 a_c1 = self.commit_in_repo(repos['a'], message='c1')
379 roll_result = self.run_roll(repos['b']) 399 roll_result = self.run_roll(repos['b'])
380 self.assertTrue(roll_result['success']) 400 self.assertTrue(roll_result['success'])
381 self.assertTrue(roll_result['trivial']) 401 self.assertTrue(roll_result['trivial'])
382 picked_roll = roll_result['picked_roll_details'] 402 picked_roll = roll_result['picked_roll_details']
383 self.assertEqual( 403 self.assertEqual(
384 str(b_package_spec.dump()).replace( 404 str(b_package_spec.dump()).replace(
385 repos['a']['revision'], a_c1['revision']), 405 repos['a']['revision'], a_c1['revision']),
386 roll_result['picked_roll_details']['spec']) 406 roll_result['picked_roll_details']['spec'])
387 407
388 # Commit the roll. 408 # Commit the roll.
389 b_c2 = self.commit_in_repo(repos['b'], message='roll') 409 b_c2 = self.commit_in_repo(repos['b'], message='roll')
390 410
391 # Change API of the recipe module in an incompatible way. 411 # Change API of the recipe module in an incompatible way.
392 b_c3 = self.update_recipe_module(repos['b'], 'b_module', {'baz': ['baz']}) 412 self.update_recipe_module(repos['b'], 'b_module', {'baz': ['baz']})
393 413
394 roll_result = self.run_roll(repos['c']) 414 roll_result = self.run_roll(repos['c'])
395 self.assertTrue(roll_result['success']) 415 self.assertTrue(roll_result['success'])
396 self.assertTrue(roll_result['trivial']) 416 self.assertTrue(roll_result['trivial'])
397 417
398 expected_picked_roll = { 418 expected_picked_roll = {
399 'commit_infos': { 419 'commit_infos': {
400 'a': [ 420 'a': [
401 { 421 {
402 'author': a_c1['author_email'], 422 'author': a_c1['author_email'],
(...skipping 25 matching lines...) Expand all
428 0, picked_roll['recipes_simulation_test']['rc']) 448 0, picked_roll['recipes_simulation_test']['rc'])
429 449
430 def test_no_backwards_roll(self): 450 def test_no_backwards_roll(self):
431 """Tests that we never roll backwards. 451 """Tests that we never roll backwards.
432 """ 452 """
433 repos = self.repo_setup({ 453 repos = self.repo_setup({
434 'a': [], 454 'a': [],
435 'b': ['a'], 455 'b': ['a'],
436 'c': ['b', 'a'], 456 'c': ['b', 'a'],
437 }) 457 })
438 root_repo_spec = self.get_root_repo_spec(repos['c']) 458 self.get_root_repo_spec(repos['c'])
439 b_repo_spec = self.get_git_repo_spec(repos['b']) 459 b_repo_spec = self.get_git_repo_spec(repos['b'])
440 c_package_spec = self.get_package_spec(repos['c']) 460 c_package_spec = self.get_package_spec(repos['c'])
441 461
442 # Create a new commit in A repo and roll it to B. 462 # Create a new commit in A repo and roll it to B.
443 a_c1 = self.commit_in_repo(repos['a'], message='c1') 463 a_c1 = self.commit_in_repo(repos['a'], message='c1')
444 b_c1_rev = self.update_recipes_cfg( 464 b_c1_rev = self.update_recipes_cfg(
445 'b', self.updated_package_spec_pb(repos['b'], 'a', a_c1['revision'])) 465 'b', self.updated_package_spec_pb(repos['b'], 'a', a_c1['revision']))
446 466
447 # Roll above commits to C. 467 # Roll above commits to C.
448 roll_result = self.run_roll(repos['c']) 468 roll_result = self.run_roll(repos['c'])
449 self.assertTrue(roll_result['success']) 469 self.assertTrue(roll_result['success'])
450 self.assertTrue(roll_result['trivial']) 470 self.assertTrue(roll_result['trivial'])
451 picked_roll = roll_result['picked_roll_details'] 471 picked_roll = roll_result['picked_roll_details']
452 self.assertEqual( 472 self.assertEqual(
453 str(c_package_spec.dump()).replace( 473 str(c_package_spec.dump()).replace(
454 repos['a']['revision'], a_c1['revision']).replace( 474 repos['a']['revision'], a_c1['revision']).replace(
455 repos['b']['revision'], b_c1_rev), 475 repos['b']['revision'], b_c1_rev),
456 roll_result['picked_roll_details']['spec']) 476 picked_roll['spec'])
457 477
458 # Create a new commit in B that would result in backwards roll. 478 # Create a new commit in B that would result in backwards roll.
459 b_c2_rev = self.update_recipes_cfg( 479 b_c2_rev = self.update_recipes_cfg(
460 'b', self.updated_package_spec_pb( 480 'b', self.updated_package_spec_pb(
461 repos['b'], 'a', repos['a']['revision'])) 481 repos['b'], 'a', repos['a']['revision']))
462 482
463 roll_result = self.run_roll(repos['c']) 483 roll_result = self.run_roll(repos['c'])
464 self.assertFalse(roll_result['success']) 484 self.assertFalse(roll_result['success'])
465 self.assertEqual([], roll_result['roll_details']) 485 self.assertEqual([], roll_result['roll_details'])
466 486
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
503 '--project=c', 523 '--project=c',
504 '--project=d', 524 '--project=d',
505 ) 525 )
506 self.assertFalse(roll_result['success']) 526 self.assertFalse(roll_result['success'])
507 self.assertFalse(bool(roll_result['roll_details'])) 527 self.assertFalse(bool(roll_result['roll_details']))
508 self.assertFalse(bool(roll_result['rejected_candidates_details'])) 528 self.assertFalse(bool(roll_result['rejected_candidates_details']))
509 529
510 530
511 if __name__ == '__main__': 531 if __name__ == '__main__':
512 sys.exit(unittest.main()) 532 sys.exit(unittest.main())
OLDNEW
« no previous file with comments | « recipe_engine/autoroll.py ('k') | unittests/repo_test_util.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698