OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Unit tests for pending_manager.py.""" | 6 """Unit tests for pending_manager.py.""" |
7 | 7 |
8 import logging | 8 import logging |
9 import os | 9 import os |
10 import re | 10 import re |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 try: | 75 try: |
76 pc.load(filename) | 76 pc.load(filename) |
77 self.assertEqual(pc.queue.pending_commits, {}) | 77 self.assertEqual(pc.queue.pending_commits, {}) |
78 pc.save(filename) | 78 pc.save(filename) |
79 self.assertEqual(trim(empty), trim(read(filename))) | 79 self.assertEqual(trim(empty), trim(read(filename))) |
80 finally: | 80 finally: |
81 os.remove(filename) | 81 os.remove(filename) |
82 if os.path.exists(filename + '.old'): | 82 if os.path.exists(filename + '.old'): |
83 os.remove(filename + '.old') | 83 os.remove(filename + '.old') |
84 | 84 |
85 def _get_pc(self, verifiers_no_patch, verifiers): | 85 def _get_pc(self, verifiers_no_patch, verifiers, |
| 86 revert_verifiers_no_patch=None, revert_verifiers=None): |
86 return pending_manager.PendingManager( | 87 return pending_manager.PendingManager( |
87 self.context, verifiers_no_patch, verifiers) | 88 self.context, verifiers_no_patch, verifiers, revert_verifiers_no_patch, |
| 89 revert_verifiers) |
88 | 90 |
89 def _check_standard_verification(self, pc, success, defered): | 91 def _check_standard_verification(self, pc, success, defered): |
90 """Verifies the checkout and rietveld calls.""" | 92 """Verifies the checkout and rietveld calls.""" |
91 pc.scan_results() | 93 pc.scan_results() |
92 self.assertEqual(len(pc.queue.iterate()), 0) | 94 self.assertEqual(len(pc.queue.iterate()), 0) |
93 issue = 31337 | 95 issue = 31337 |
94 if pc.verifiers: | 96 if pc.verifiers: |
95 if success: | 97 if success: |
96 self.context.checkout.check_calls( | 98 self.context.checkout.check_calls( |
97 [ 'prepare(None)', | 99 [ 'prepare(None)', |
98 'apply_patch(%r)' % (self.context.rietveld.patchsets[0],), | 100 'apply_patch(%r, revert=False)' % ( |
| 101 self.context.rietveld.patchsets[0]), |
99 'prepare(None)', # Will sync to HEAD/124. | 102 'prepare(None)', # Will sync to HEAD/124. |
100 'apply_patch(%r)' % (self.context.rietveld.patchsets[1],), | 103 'apply_patch(%r, revert=False)' % ( |
| 104 self.context.rietveld.patchsets[1]), |
101 ( | 105 ( |
102 "commit(u'foo\\n\\n" | 106 "commit(u'foo\\n\\n" |
103 "Review URL: http://nowhere/%d', " | 107 "Review URL: http://nowhere/%d', " |
104 "u'author@example.com')") % issue]) | 108 "u'author@example.com')") % issue]) |
105 self.context.rietveld.check_calls( | 109 self.context.rietveld.check_calls( |
106 [ _try_comment(), | 110 [ _try_comment(), |
107 'close_issue(%d)' % issue, | 111 'close_issue(%d)' % issue, |
108 "update_description(%d, u'foo')" % issue, | 112 "update_description(%d, u'foo')" % issue, |
109 "add_comment(%d, 'Change committed as 125')" % issue]) | 113 "add_comment(%d, 'Change committed as 125')" % issue]) |
110 else: | 114 else: |
111 self.context.checkout.check_calls( | 115 self.context.checkout.check_calls( |
112 [ 'prepare(None)', | 116 [ 'prepare(None)', |
113 'apply_patch(%r)' % (self.context.rietveld.patchsets[0],)]) | 117 'apply_patch(%r, revert=False)' % ( |
| 118 self.context.rietveld.patchsets[0])]) |
114 self.context.rietveld.check_calls( | 119 self.context.rietveld.check_calls( |
115 [ _try_comment(), | 120 [ _try_comment(), |
116 "set_flag(%d, 1, 'commit', 'False')" % issue, | 121 "set_flag(%d, 1, 'commit', 'False')" % issue, |
117 "add_comment(%d, %r)" % (issue, pc.FAILED_NO_MESSAGE)]) | 122 "add_comment(%d, %r)" % (issue, pc.FAILED_NO_MESSAGE)]) |
118 else: | 123 else: |
119 if success: | 124 if success: |
120 self.context.checkout.check_calls( | 125 self.context.checkout.check_calls( |
121 self._prepare_apply_commit(0, issue)) | 126 self._prepare_apply_commit(0, issue)) |
122 self.context.rietveld.check_calls( | 127 self.context.rietveld.check_calls( |
123 [ _try_comment(), | 128 [ _try_comment(), |
124 'close_issue(%d)' % issue, | 129 'close_issue(%d)' % issue, |
125 "update_description(%d, u'foo')" % issue, | 130 "update_description(%d, u'foo')" % issue, |
126 "add_comment(%d, 'Change committed as 125')" % issue]) | 131 "add_comment(%d, 'Change committed as 125')" % issue]) |
127 else: | 132 else: |
128 # checkout is never touched in that case. | 133 # checkout is never touched in that case. |
129 self.context.checkout.check_calls([]) | 134 self.context.checkout.check_calls([]) |
130 if defered: | 135 if defered: |
131 self.context.rietveld.check_calls( | 136 self.context.rietveld.check_calls( |
132 [ _try_comment(), | 137 [ _try_comment(), |
133 "set_flag(%d, 1, 'commit', 'False')" % issue, | 138 "set_flag(%d, 1, 'commit', 'False')" % issue, |
134 "add_comment(%d, %r)" % (issue, pc.FAILED_NO_MESSAGE)]) | 139 "add_comment(%d, %r)" % (issue, pc.FAILED_NO_MESSAGE)]) |
135 else: | 140 else: |
136 self.context.rietveld.check_calls( | 141 self.context.rietveld.check_calls( |
137 [ "set_flag(%d, 1, 'commit', 'False')" % issue, | 142 [ "set_flag(%d, 1, 'commit', 'False')" % issue, |
138 "add_comment(%d, %r)" % (issue, pc.FAILED_NO_MESSAGE)]) | 143 "add_comment(%d, %r)" % (issue, pc.FAILED_NO_MESSAGE)]) |
139 | 144 |
140 def _prepare_apply_commit(self, index, issue, server_hooks_missing=False): | 145 def _prepare_apply_commit(self, index, issue, server_hooks_missing=False, |
| 146 revert=False): |
141 """Returns a frequent sequence of action happening on the Checkout object. | 147 """Returns a frequent sequence of action happening on the Checkout object. |
142 | 148 |
143 The list returned by this function should be used as an argument to | 149 The list returned by this function should be used as an argument to |
144 self.context.checkout.check_calls(). | 150 self.context.checkout.check_calls(). |
145 """ | 151 """ |
146 seq = [ | 152 seq = [ |
147 # Reverts any previous modification or checkout the tree if it was not | 153 # Reverts any previous modification or checkout the tree if it was not |
148 # present. | 154 # present. |
149 'prepare(None)', | 155 'prepare(None)', |
150 # Applies the requested PatchSet. | 156 # Applies the requested PatchSet. |
151 'apply_patch(%r)' % self.context.rietveld.patchsets[index], | 157 'apply_patch(%r, revert=%s)' % (self.context.rietveld.patchsets[index], |
| 158 revert), |
152 ] | 159 ] |
153 # Commits the patch. | 160 # Commits the patch. |
154 author_and_reviewer = '' | 161 author_and_reviewer = '' |
155 if server_hooks_missing: | 162 if server_hooks_missing: |
156 author_and_reviewer = ( | 163 author_and_reviewer = ( |
157 '\\n\\nR=rev@example.com\\n\\nAuthor: author@example.com') | 164 '\\n\\nR=rev@example.com\\n\\nAuthor: author@example.com') |
| 165 desc = 'foo' |
| 166 if revert: |
| 167 desc = 'Revert of: ' + desc |
158 commit_message = ( | 168 commit_message = ( |
159 "commit(u'foo%s\\n\\n" | 169 "commit(u'%s%s\\n\\n" |
160 "Review URL: http://nowhere/%d', " | 170 "Review URL: http://nowhere/%d', " |
161 "u'author@example.com')") % (author_and_reviewer, issue) | 171 "u'author@example.com')") % (desc, author_and_reviewer, issue) |
162 seq.append(commit_message) | 172 seq.append(commit_message) |
163 | 173 |
164 return seq | 174 return seq |
165 | 175 |
166 def testNoVerification(self): | 176 def testNoVerification(self): |
167 try: | 177 try: |
168 # Need at least one verification. | 178 # Need at least one verification. |
169 self._get_pc([], []) | 179 self._get_pc([], []) |
170 self.fail() | 180 self.fail() |
171 except AssertionError: | 181 except AssertionError: |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 pc.look_for_new_pending_commit() | 261 pc.look_for_new_pending_commit() |
252 self.assertEqual(len(pc.queue.iterate()), 1) | 262 self.assertEqual(len(pc.queue.iterate()), 1) |
253 commit = pc.queue.get(issue) | 263 commit = pc.queue.get(issue) |
254 self.assertEqual(len(commit.verifications), 0) | 264 self.assertEqual(len(commit.verifications), 0) |
255 pc.process_new_pending_commit() | 265 pc.process_new_pending_commit() |
256 self.assertEqual([], pc.queue.iterate()) | 266 self.assertEqual([], pc.queue.iterate()) |
257 pc.update_status() | 267 pc.update_status() |
258 self.assertEqual([], pc.queue.iterate()) | 268 self.assertEqual([], pc.queue.iterate()) |
259 self.context.checkout.check_calls( | 269 self.context.checkout.check_calls( |
260 [ 'prepare(None)', | 270 [ 'prepare(None)', |
261 'apply_patch(%r)' % (self.context.rietveld.patchsets[0],), | 271 'apply_patch(%r, revert=False)' % ( |
| 272 self.context.rietveld.patchsets[0]), |
262 ]) | 273 ]) |
263 self.context.rietveld.check_calls( | 274 self.context.rietveld.check_calls( |
264 [ _try_comment(), | 275 [ _try_comment(), |
265 "add_comment(%d, %r)" % (issue, pc.FAILED_NO_MESSAGE), | 276 "add_comment(%d, %r)" % (issue, pc.FAILED_NO_MESSAGE), |
266 ]) | 277 ]) |
267 self.context.status.check_names(['initial', 'abort']) | 278 self.context.status.check_names(['initial', 'abort']) |
268 | 279 |
269 def _check_defer_1(self, pc, result): | 280 def _check_defer_1(self, pc, result): |
270 issue = 31337 | 281 issue = 31337 |
271 self.assertEqual(len(pc.queue.iterate()), 0) | 282 self.assertEqual(len(pc.queue.iterate()), 0) |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 [r'^%s(.*)$' % re.escape(r'http://example.com/')]), | 439 [r'^%s(.*)$' % re.escape(r'http://example.com/')]), |
429 ] | 440 ] |
430 pc = self._get_pc([], verifiers) | 441 pc = self._get_pc([], verifiers) |
431 pc.context.rietveld.issues[issue]['base_url'] = 'http://example.com/sub/dir' | 442 pc.context.rietveld.issues[issue]['base_url'] = 'http://example.com/sub/dir' |
432 pc.look_for_new_pending_commit() | 443 pc.look_for_new_pending_commit() |
433 self.assertEqual(1, len(pc.queue.iterate())) | 444 self.assertEqual(1, len(pc.queue.iterate())) |
434 pc.process_new_pending_commit() | 445 pc.process_new_pending_commit() |
435 self.assertEqual('sub/dir', pc.queue.get(issue).relpath) | 446 self.assertEqual('sub/dir', pc.queue.get(issue).relpath) |
436 self.context.checkout.check_calls( | 447 self.context.checkout.check_calls( |
437 [ 'prepare(None)', | 448 [ 'prepare(None)', |
438 'apply_patch(%r)' % (self.context.rietveld.patchsets[0],)]) | 449 'apply_patch(%r, revert=False)' % ( |
| 450 self.context.rietveld.patchsets[0])]) |
439 pc.update_status() | 451 pc.update_status() |
440 self.context.checkout.check_calls([]) | 452 self.context.checkout.check_calls([]) |
441 pc.scan_results() | 453 pc.scan_results() |
442 self.context.checkout.check_calls( | 454 self.context.checkout.check_calls( |
443 # Will sync to HEAD, 124. | 455 # Will sync to HEAD, 124. |
444 self._prepare_apply_commit(1, issue)) | 456 self._prepare_apply_commit(1, issue)) |
445 self.context.rietveld.check_calls( | 457 self.context.rietveld.check_calls( |
446 [ _try_comment(), | 458 [ _try_comment(), |
447 'close_issue(%d)' % issue, | 459 'close_issue(%d)' % issue, |
448 "update_description(%d, u'foo')" % issue, | 460 "update_description(%d, u'foo')" % issue, |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
523 self._prepare_apply_commit(next_item + 2, issue)) | 535 self._prepare_apply_commit(next_item + 2, issue)) |
524 self.context.rietveld.check_calls( | 536 self.context.rietveld.check_calls( |
525 [ 'close_issue(%d)' % (next_item + 1), | 537 [ 'close_issue(%d)' % (next_item + 1), |
526 "update_description(%d, u'foo')" % (next_item + 1), | 538 "update_description(%d, u'foo')" % (next_item + 1), |
527 "add_comment(%d, 'Change committed as 125')" % (next_item + 1), | 539 "add_comment(%d, 'Change committed as 125')" % (next_item + 1), |
528 'close_issue(%d)' % issue, | 540 'close_issue(%d)' % issue, |
529 "update_description(%d, u'foo')" % issue, | 541 "update_description(%d, u'foo')" % issue, |
530 "add_comment(%d, 'Change committed as 125')" % issue]) | 542 "add_comment(%d, 'Change committed as 125')" % issue]) |
531 self.context.status.check_names(['why not', 'commit'] * 2) | 543 self.context.status.check_names(['why not', 'commit'] * 2) |
532 | 544 |
| 545 def testRevertBurst(self): |
| 546 issue = 31337 |
| 547 pc = self._get_pc( |
| 548 verifiers_no_patch=[fake.FakeVerifier(base.SUCCEEDED)], |
| 549 verifiers=[], |
| 550 revert_verifiers_no_patch=[fake.FakeVerifier(base.SUCCEEDED)], |
| 551 revert_verifiers=[]) |
| 552 self.assertEqual(4, pc.MAX_COMMIT_BURST) |
| 553 timestamp = [1] |
| 554 self.mock(time, 'time', lambda: timestamp[-1]) |
| 555 # Set test issues to 'revert' issues, 31337 will still be a regular commit. |
| 556 for i in range(pc.MAX_COMMIT_BURST + 2): |
| 557 rietveld_issue = self.context.rietveld.issues[issue].copy() |
| 558 rietveld_issue['closed'] = True |
| 559 rietveld_issue['commit'] = False |
| 560 rietveld_issue['revert'] = True |
| 561 rietveld_issue['reverted_by'] = 'xyz@example.com' |
| 562 self.context.rietveld.issues[i] = rietveld_issue |
| 563 self.context.rietveld.issues[i]['issue'] = i |
| 564 pc.look_for_new_pending_commit() |
| 565 self.assertEqual(len(pc.queue.iterate()), pc.MAX_COMMIT_BURST + 3) |
| 566 pc.process_new_pending_commit() |
| 567 pc.update_status() |
| 568 pc.scan_results() |
| 569 self.context.checkout.check_calls( |
| 570 self._prepare_apply_commit(0, 0, False, True) + |
| 571 self._prepare_apply_commit(1, 1, False, True) + |
| 572 self._prepare_apply_commit(2, 2, False, True) + |
| 573 self._prepare_apply_commit(3, 3, False, True)) |
| 574 self.context.rietveld.check_calls( |
| 575 [ _try_comment(0), |
| 576 _try_comment(1), |
| 577 _try_comment(2), |
| 578 _try_comment(3), |
| 579 _try_comment(4), |
| 580 _try_comment(5), |
| 581 _try_comment(), |
| 582 'open_issue(0)', |
| 583 "update_description(0, u'foo')", |
| 584 "add_comment(0, 'Change reverted as 125')", |
| 585 'open_issue(1)', |
| 586 "update_description(1, u'foo')", |
| 587 "add_comment(1, 'Change reverted as 125')", |
| 588 'open_issue(2)', |
| 589 "update_description(2, u'foo')", |
| 590 "add_comment(2, 'Change reverted as 125')", |
| 591 'open_issue(3)', |
| 592 "update_description(3, u'foo')", |
| 593 "add_comment(3, 'Change reverted as 125')", |
| 594 ]) |
| 595 self.assertEqual(3, len(pc.queue.iterate())) |
| 596 total = pc.MAX_COMMIT_BURST + 3 |
| 597 self.context.status.check_names(['initial'] * total + |
| 598 (['why not', 'commit'] * |
| 599 pc.MAX_COMMIT_BURST) + |
| 600 ['why not'] * 3) |
| 601 |
| 602 # Dry run. |
| 603 pc.scan_results() |
| 604 self.context.checkout.check_calls([]) |
| 605 self.context.rietveld.check_calls([]) |
| 606 self.context.status.check_names(['why not'] * 3) |
| 607 |
| 608 # Remove one item from the burst. |
| 609 pc.recent_commit_timestamps.pop() |
| 610 pc.scan_results() |
| 611 next_item = pc.MAX_COMMIT_BURST |
| 612 self.context.checkout.check_calls( |
| 613 self._prepare_apply_commit(next_item, next_item, False, True)) |
| 614 self.context.rietveld.check_calls( |
| 615 [ 'open_issue(%d)' % next_item, |
| 616 "update_description(%d, u'foo')" % next_item, |
| 617 "add_comment(%d, 'Change reverted as 125')" % next_item, |
| 618 ]) |
| 619 self.context.status.check_names(['why not', 'commit'] + ['why not'] * 2) |
| 620 # After a delay, must flush the queue. |
| 621 timestamp.append(timestamp[-1] + pc.COMMIT_BURST_DELAY + 1) |
| 622 pc.scan_results() |
| 623 self.context.checkout.check_calls( |
| 624 self._prepare_apply_commit(next_item + 1, next_item + 1, False, True) + |
| 625 self._prepare_apply_commit(next_item + 2, issue, False, False)) |
| 626 self.context.rietveld.check_calls( |
| 627 [ 'open_issue(%d)' % (next_item + 1), |
| 628 "update_description(%d, u'foo')" % (next_item + 1), |
| 629 "add_comment(%d, 'Change reverted as 125')" % (next_item + 1), |
| 630 'close_issue(%d)' % issue, |
| 631 "update_description(%d, u'foo')" % issue, |
| 632 "add_comment(%d, 'Change committed as 125')" % issue]) |
| 633 self.context.status.check_names(['why not', 'commit'] * 2) |
| 634 |
533 def testIgnored(self): | 635 def testIgnored(self): |
534 issue = 31337 | 636 issue = 31337 |
535 verifiers = [ | 637 verifiers = [ |
536 project_base.ProjectBaseUrlVerifier( | 638 project_base.ProjectBaseUrlVerifier( |
537 [r'^%s(.*)$' % re.escape(r'http://example.com/')]), | 639 [r'^%s(.*)$' % re.escape(r'http://example.com/')]), |
538 ] | 640 ] |
539 pc = self._get_pc(verifiers, []) | 641 pc = self._get_pc(verifiers, []) |
540 pc.context.rietveld.issues[issue]['base_url'] = 'http://unrelated.com/sub' | 642 pc.context.rietveld.issues[issue]['base_url'] = 'http://unrelated.com/sub' |
541 pc.look_for_new_pending_commit() | 643 pc.look_for_new_pending_commit() |
542 pc.process_new_pending_commit() | 644 pc.process_new_pending_commit() |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
720 self.context.checkout.check_calls( | 822 self.context.checkout.check_calls( |
721 self._prepare_apply_commit(0, issue)) | 823 self._prepare_apply_commit(0, issue)) |
722 | 824 |
723 | 825 |
724 if __name__ == '__main__': | 826 if __name__ == '__main__': |
725 logging.basicConfig( | 827 logging.basicConfig( |
726 level=[logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG][ | 828 level=[logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG][ |
727 min(sys.argv.count('-v'), 3)], | 829 min(sys.argv.count('-v'), 3)], |
728 format='%(levelname)5s %(module)15s(%(lineno)3d): %(message)s') | 830 format='%(levelname)5s %(module)15s(%(lineno)3d): %(message)s') |
729 unittest.main() | 831 unittest.main() |
OLD | NEW |