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

Side by Side Diff: tests/presubmit_unittest.py

Issue 1927773002: Reland Implement owners check in presubmit for Gerrit. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@P300
Patch Set: gerrit fix Created 4 years, 7 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 | « presubmit_support.py ('k') | no next file » | 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 (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 presubmit_support.py and presubmit_canned_checks.py.""" 6 """Unit tests for presubmit_support.py and presubmit_canned_checks.py."""
7 7
8 # pylint: disable=E1101,E1103 8 # pylint: disable=E1101,E1103
9 9
10 import StringIO 10 import StringIO
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 'NonexistantCannedCheckFilter', 'OutputApi', 'ParseFiles', 177 'NonexistantCannedCheckFilter', 'OutputApi', 'ParseFiles',
178 'PresubmitFailure', 'PresubmitExecuter', 'PresubmitOutput', 'ScanSubDirs', 178 'PresubmitFailure', 'PresubmitExecuter', 'PresubmitOutput', 'ScanSubDirs',
179 'SvnAffectedFile', 'SvnChange', 'auth', 'cPickle', 'cpplint', 'cStringIO', 179 'SvnAffectedFile', 'SvnChange', 'auth', 'cPickle', 'cpplint', 'cStringIO',
180 'contextlib', 'canned_check_filter', 'fix_encoding', 'fnmatch', 180 'contextlib', 'canned_check_filter', 'fix_encoding', 'fnmatch',
181 'gclient_utils', 'glob', 'inspect', 'json', 'load_files', 'logging', 181 'gclient_utils', 'glob', 'inspect', 'json', 'load_files', 'logging',
182 'marshal', 'normpath', 'optparse', 'os', 'owners', 'pickle', 182 'marshal', 'normpath', 'optparse', 'os', 'owners', 'pickle',
183 'presubmit_canned_checks', 'random', 're', 'rietveld', 'scm', 183 'presubmit_canned_checks', 'random', 're', 'rietveld', 'scm',
184 'subprocess', 'sys', 'tempfile', 'time', 'traceback', 'types', 'unittest', 184 'subprocess', 'sys', 'tempfile', 'time', 'traceback', 'types', 'unittest',
185 'urllib2', 'warn', 'multiprocessing', 'DoGetTryMasters', 185 'urllib2', 'warn', 'multiprocessing', 'DoGetTryMasters',
186 'GetTryMastersExecuter', 'itertools', 'urlparse', 'gerrit_util', 186 'GetTryMastersExecuter', 'itertools', 'urlparse', 'gerrit_util',
187 'GerritAccessor',
187 ] 188 ]
188 # If this test fails, you should add the relevant test. 189 # If this test fails, you should add the relevant test.
189 self.compareMembers(presubmit, members) 190 self.compareMembers(presubmit, members)
190 191
191 def testCannedCheckFilter(self): 192 def testCannedCheckFilter(self):
192 canned = presubmit.presubmit_canned_checks 193 canned = presubmit.presubmit_canned_checks
193 orig = canned.CheckOwners 194 orig = canned.CheckOwners
194 with presubmit.canned_check_filter(['CheckOwners']): 195 with presubmit.canned_check_filter(['CheckOwners']):
195 self.assertNotEqual(canned.CheckOwners, orig) 196 self.assertNotEqual(canned.CheckOwners, orig)
196 self.assertEqual(canned.CheckOwners(None, None), []) 197 self.assertEqual(canned.CheckOwners(None, None), [])
(...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after
821 # Always fail. 822 # Always fail.
822 change = presubmit.Change( 823 change = presubmit.Change(
823 'mychange', 824 'mychange',
824 '\n'.join(description_lines), 825 '\n'.join(description_lines),
825 self.fake_root_dir, 826 self.fake_root_dir,
826 files, 827 files,
827 0, 828 0,
828 0, 829 0,
829 None) 830 None)
830 output = presubmit.DoPresubmitChecks( 831 output = presubmit.DoPresubmitChecks(
831 change, False, True, None, input_buf, DEFAULT_SCRIPT, False, None) 832 change, False, True, None, input_buf, DEFAULT_SCRIPT, False, None, None,
833 None)
832 self.failIf(output.should_continue()) 834 self.failIf(output.should_continue())
833 text = ( 835 text = (
834 'Running presubmit upload checks ...\n' 836 'Running presubmit upload checks ...\n'
835 'Warning, no PRESUBMIT.py found.\n' 837 'Warning, no PRESUBMIT.py found.\n'
836 'Running default presubmit script.\n' 838 'Running default presubmit script.\n'
837 '\n' 839 '\n'
838 '** Presubmit ERRORS **\n!!\n\n' 840 '** Presubmit ERRORS **\n!!\n\n'
839 'Was the presubmit check useful? If not, run "git cl presubmit -v"\n' 841 'Was the presubmit check useful? If not, run "git cl presubmit -v"\n'
840 'to figure out which PRESUBMIT.py was run, then run git blame\n' 842 'to figure out which PRESUBMIT.py was run, then run git blame\n'
841 'on the file to figure out who to ask for help.\n') 843 'on the file to figure out who to ask for help.\n')
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
903 input_buf = StringIO.StringIO('y\n') 905 input_buf = StringIO.StringIO('y\n')
904 change = presubmit.Change( 906 change = presubmit.Change(
905 'foo', 907 'foo',
906 'Blah Blah\n\nSTORY=http://tracker.com/42\nBUG=boo\n', 908 'Blah Blah\n\nSTORY=http://tracker.com/42\nBUG=boo\n',
907 self.fake_root_dir, 909 self.fake_root_dir,
908 None, 910 None,
909 0, 911 0,
910 0, 912 0,
911 None) 913 None)
912 self.failUnless(presubmit.DoPresubmitChecks( 914 self.failUnless(presubmit.DoPresubmitChecks(
913 change, False, True, output, input_buf, DEFAULT_SCRIPT, False, None)) 915 change, False, True, output, input_buf, DEFAULT_SCRIPT, False, None,
916 None))
914 self.assertEquals(output.getvalue(), 917 self.assertEquals(output.getvalue(),
915 ('Running presubmit upload checks ...\n' 918 ('Running presubmit upload checks ...\n'
916 'Warning, no PRESUBMIT.py found.\n' 919 'Warning, no PRESUBMIT.py found.\n'
917 'Running default presubmit script.\n' 920 'Running default presubmit script.\n'
918 '\n' 921 '\n'
919 '** Presubmit Messages **\n' 922 '** Presubmit Messages **\n'
920 'http://tracker.com/42\n' 923 'http://tracker.com/42\n'
921 '\n' 924 '\n'
922 'Presubmit checks passed.\n')) 925 'Presubmit checks passed.\n'))
923 926
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
1146 self.mox.StubOutWithMock(presubmit, 'ParseFiles') 1149 self.mox.StubOutWithMock(presubmit, 'ParseFiles')
1147 presubmit.scm.determine_scm(self.fake_root_dir).AndReturn(None) 1150 presubmit.scm.determine_scm(self.fake_root_dir).AndReturn(None)
1148 presubmit.ParseFiles(['random_file.txt'], None 1151 presubmit.ParseFiles(['random_file.txt'], None
1149 ).AndReturn([('M', 'random_file.txt')]) 1152 ).AndReturn([('M', 'random_file.txt')])
1150 output = self.mox.CreateMock(presubmit.PresubmitOutput) 1153 output = self.mox.CreateMock(presubmit.PresubmitOutput)
1151 output.should_continue().AndReturn(False) 1154 output.should_continue().AndReturn(False)
1152 1155
1153 presubmit.DoPresubmitChecks(mox.IgnoreArg(), False, False, 1156 presubmit.DoPresubmitChecks(mox.IgnoreArg(), False, False,
1154 mox.IgnoreArg(), 1157 mox.IgnoreArg(),
1155 mox.IgnoreArg(), 1158 mox.IgnoreArg(),
1156 None, False, None, None).AndReturn(output) 1159 None, False, None, None, None).AndReturn(output)
1157 self.mox.ReplayAll() 1160 self.mox.ReplayAll()
1158 1161
1159 self.assertEquals( 1162 self.assertEquals(
1160 True, 1163 True,
1161 presubmit.main(['--root', self.fake_root_dir, 'random_file.txt'])) 1164 presubmit.main(['--root', self.fake_root_dir, 'random_file.txt']))
1162 1165
1163 def testMainUnversionedFail(self): 1166 def testMainUnversionedFail(self):
1164 # OptParser calls presubmit.os.path.exists and is a pain when mocked. 1167 # OptParser calls presubmit.os.path.exists and is a pain when mocked.
1165 self.UnMock(presubmit.os.path, 'exists') 1168 self.UnMock(presubmit.os.path, 'exists')
1166 self.mox.StubOutWithMock(presubmit, 'DoPresubmitChecks') 1169 self.mox.StubOutWithMock(presubmit, 'DoPresubmitChecks')
(...skipping 23 matching lines...) Expand all
1190 'AbsoluteLocalPaths', 'AffectedFiles', 'AffectedSourceFiles', 1193 'AbsoluteLocalPaths', 'AffectedFiles', 'AffectedSourceFiles',
1191 'AffectedTextFiles', 'DEFAULT_BLACK_LIST', 'DEFAULT_WHITE_LIST', 1194 'AffectedTextFiles', 'DEFAULT_BLACK_LIST', 'DEFAULT_WHITE_LIST',
1192 'DepotToLocalPath', 'FilterSourceFile', 'LocalPaths', 'LocalToDepotPath', 1195 'DepotToLocalPath', 'FilterSourceFile', 'LocalPaths', 'LocalToDepotPath',
1193 'Command', 'RunTests', 'PresubmitLocalPath', 'ReadFile', 1196 'Command', 'RunTests', 'PresubmitLocalPath', 'ReadFile',
1194 'RightHandSideLines', 'ServerPaths', 'basename', 'cPickle', 'cpplint', 1197 'RightHandSideLines', 'ServerPaths', 'basename', 'cPickle', 'cpplint',
1195 'cStringIO', 'canned_checks', 'change', 'cpu_count', 'environ', 'glob', 1198 'cStringIO', 'canned_checks', 'change', 'cpu_count', 'environ', 'glob',
1196 'host_url', 'is_committing', 'json', 'logging', 'marshal', 'os_listdir', 1199 'host_url', 'is_committing', 'json', 'logging', 'marshal', 'os_listdir',
1197 'os_walk', 'os_path', 'os_stat', 'owners_db', 'pickle', 'platform', 1200 'os_walk', 'os_path', 'os_stat', 'owners_db', 'pickle', 'platform',
1198 'python_executable', 're', 'rietveld', 'subprocess', 'tbr', 'tempfile', 1201 'python_executable', 're', 'rietveld', 'subprocess', 'tbr', 'tempfile',
1199 'time', 'traceback', 'unittest', 'urllib2', 'version', 'verbose', 1202 'time', 'traceback', 'unittest', 'urllib2', 'version', 'verbose',
1200 'dry_run', 1203 'dry_run', 'gerrit',
1201 ] 1204 ]
1202 # If this test fails, you should add the relevant test. 1205 # If this test fails, you should add the relevant test.
1203 self.compareMembers( 1206 self.compareMembers(
1204 presubmit.InputApi(self.fake_change, './.', False, None, False), 1207 presubmit.InputApi(self.fake_change, './.', False, None, False),
1205 members) 1208 members)
1206 1209
1207 def testDepotToLocalPath(self): 1210 def testDepotToLocalPath(self):
1208 presubmit.scm.SVN._CaptureInfo(['svn://foo/smurf'], self.fake_root_dir 1211 presubmit.scm.SVN._CaptureInfo(['svn://foo/smurf'], self.fake_root_dir
1209 ).AndReturn({'Path': 'prout'}) 1212 ).AndReturn({'Path': 'prout'})
1210 presubmit.scm.SVN._CaptureInfo( 1213 presubmit.scm.SVN._CaptureInfo(
(...skipping 621 matching lines...) Expand 10 before | Expand all | Expand 10 after
1832 # pylint: disable=R0201 1835 # pylint: disable=R0201
1833 input_api = self.mox.CreateMock(presubmit.InputApi) 1836 input_api = self.mox.CreateMock(presubmit.InputApi)
1834 input_api.cStringIO = presubmit.cStringIO 1837 input_api.cStringIO = presubmit.cStringIO
1835 input_api.json = presubmit.json 1838 input_api.json = presubmit.json
1836 input_api.logging = logging 1839 input_api.logging = logging
1837 input_api.os_listdir = self.mox.CreateMockAnything() 1840 input_api.os_listdir = self.mox.CreateMockAnything()
1838 input_api.os_walk = self.mox.CreateMockAnything() 1841 input_api.os_walk = self.mox.CreateMockAnything()
1839 input_api.os_path = presubmit.os.path 1842 input_api.os_path = presubmit.os.path
1840 input_api.re = presubmit.re 1843 input_api.re = presubmit.re
1841 input_api.rietveld = self.mox.CreateMock(rietveld.Rietveld) 1844 input_api.rietveld = self.mox.CreateMock(rietveld.Rietveld)
1845 input_api.gerrit = None
1842 input_api.traceback = presubmit.traceback 1846 input_api.traceback = presubmit.traceback
1843 input_api.urllib2 = self.mox.CreateMock(presubmit.urllib2) 1847 input_api.urllib2 = self.mox.CreateMock(presubmit.urllib2)
1844 input_api.unittest = unittest 1848 input_api.unittest = unittest
1845 input_api.subprocess = self.mox.CreateMock(subprocess) 1849 input_api.subprocess = self.mox.CreateMock(subprocess)
1846 presubmit.subprocess = input_api.subprocess 1850 presubmit.subprocess = input_api.subprocess
1847 class fake_CalledProcessError(Exception): 1851 class fake_CalledProcessError(Exception):
1848 def __str__(self): 1852 def __str__(self):
1849 return 'foo' 1853 return 'foo'
1850 input_api.subprocess.CalledProcessError = fake_CalledProcessError 1854 input_api.subprocess.CalledProcessError = fake_CalledProcessError
1851 input_api.verbose = False 1855 input_api.verbose = False
(...skipping 702 matching lines...) Expand 10 before | Expand all | Expand 10 after
2554 connection.close() 2558 connection.close()
2555 self.mox.ReplayAll() 2559 self.mox.ReplayAll()
2556 2560
2557 results = presubmit_canned_checks.CheckBuildbotPendingBuilds( 2561 results = presubmit_canned_checks.CheckBuildbotPendingBuilds(
2558 input_api, presubmit.OutputApi, 'uurl', 2, ('foo')) 2562 input_api, presubmit.OutputApi, 'uurl', 2, ('foo'))
2559 self.assertEquals(len(results), 1) 2563 self.assertEquals(len(results), 1)
2560 self.assertEquals(results[0].__class__, 2564 self.assertEquals(results[0].__class__,
2561 presubmit.OutputApi.PresubmitNotifyResult) 2565 presubmit.OutputApi.PresubmitNotifyResult)
2562 2566
2563 def AssertOwnersWorks(self, tbr=False, issue='1', approvers=None, 2567 def AssertOwnersWorks(self, tbr=False, issue='1', approvers=None,
2564 reviewers=None, is_committing=True, rietveld_response=None, 2568 reviewers=None, is_committing=True,
2569 rietveld_response=None, gerrit_response=None,
2565 uncovered_files=None, expected_output='', 2570 uncovered_files=None, expected_output='',
2566 manually_specified_reviewers=None, dry_run=None): 2571 manually_specified_reviewers=None, dry_run=None):
2567 if approvers is None: 2572 if approvers is None:
2568 # The set of people who lgtm'ed a change. 2573 # The set of people who lgtm'ed a change.
2569 approvers = set() 2574 approvers = set()
2570 if reviewers is None: 2575 if reviewers is None:
2571 # The set of people needed to lgtm a change. We default to 2576 # The set of people needed to lgtm a change. We default to
2572 # the same list as the people who approved it. We use 'reviewers' 2577 # the same list as the people who approved it. We use 'reviewers'
2573 # to avoid a name collision w/ owners.py. 2578 # to avoid a name collision w/ owners.py.
2574 reviewers = approvers 2579 reviewers = approvers
2575 if uncovered_files is None: 2580 if uncovered_files is None:
2576 uncovered_files = set() 2581 uncovered_files = set()
2577 if manually_specified_reviewers is None: 2582 if manually_specified_reviewers is None:
2578 manually_specified_reviewers = [] 2583 manually_specified_reviewers = []
2579 2584
2580 change = self.mox.CreateMock(presubmit.Change) 2585 change = self.mox.CreateMock(presubmit.Change)
2581 change.issue = issue 2586 change.issue = issue
2582 change.author_email = 'john@example.com' 2587 change.author_email = 'john@example.com'
2583 change.R = ','.join(manually_specified_reviewers) 2588 change.R = ','.join(manually_specified_reviewers)
2584 change.TBR = '' 2589 change.TBR = ''
2585 affected_file = self.mox.CreateMock(presubmit.SvnAffectedFile) 2590 affected_file = self.mox.CreateMock(presubmit.SvnAffectedFile)
2586 input_api = self.MockInputApi(change, False) 2591 input_api = self.MockInputApi(change, False)
2592 if gerrit_response:
2593 assert not rietveld_response
2594 input_api.rietveld = None
2595 input_api.gerrit = presubmit.GerritAccessor('host')
2596
2587 fake_db = self.mox.CreateMock(owners.Database) 2597 fake_db = self.mox.CreateMock(owners.Database)
2588 fake_db.email_regexp = input_api.re.compile(owners.BASIC_EMAIL_REGEXP) 2598 fake_db.email_regexp = input_api.re.compile(owners.BASIC_EMAIL_REGEXP)
2589 input_api.owners_db = fake_db 2599 input_api.owners_db = fake_db
2590 input_api.is_committing = is_committing 2600 input_api.is_committing = is_committing
2591 input_api.tbr = tbr 2601 input_api.tbr = tbr
2592 input_api.dry_run = dry_run 2602 input_api.dry_run = dry_run
2593 2603
2594 if not is_committing or (not tbr and issue): 2604 if not is_committing or (not tbr and issue):
2595 if not dry_run: 2605 if not dry_run:
2596 affected_file.LocalPath().AndReturn('foo/xyz.cc') 2606 affected_file.LocalPath().AndReturn('foo/xyz.cc')
2597 change.AffectedFiles(file_filter=None).AndReturn([affected_file]) 2607 change.AffectedFiles(file_filter=None).AndReturn([affected_file])
2598 if issue and not rietveld_response: 2608 if issue and not rietveld_response and not gerrit_response:
2599 rietveld_response = { 2609 rietveld_response = {
2600 "owner_email": change.author_email, 2610 "owner_email": change.author_email,
2601 "messages": [ 2611 "messages": [
2602 {"sender": a, "text": "I approve", "approval": True} 2612 {"sender": a, "text": "I approve", "approval": True}
2603 for a in approvers 2613 for a in approvers
2604 ], 2614 ],
2605 "reviewers": reviewers 2615 "reviewers": reviewers
2606 } 2616 }
2607 2617
2608 if is_committing: 2618 if is_committing:
2609 people = approvers 2619 people = approvers
2610 else: 2620 else:
2611 people = reviewers 2621 people = reviewers
2612 2622
2613 if not dry_run: 2623 if not dry_run:
2614 if issue: 2624 if issue:
2615 input_api.rietveld.get_issue_properties( 2625 if rietveld_response:
2616 issue=int(input_api.change.issue), messages=True).AndReturn( 2626 input_api.rietveld.get_issue_properties(
2617 rietveld_response) 2627 issue=int(input_api.change.issue), messages=True).AndReturn(
2628 rietveld_response)
2629 elif gerrit_response:
2630 input_api.gerrit._FetchChangeDetail = lambda _: gerrit_response
2618 2631
2619 people.add(change.author_email) 2632 people.add(change.author_email)
2620 fake_db.files_not_covered_by(set(['foo/xyz.cc']), 2633 fake_db.files_not_covered_by(set(['foo/xyz.cc']),
2621 people).AndReturn(uncovered_files) 2634 people).AndReturn(uncovered_files)
2622 if not is_committing and uncovered_files: 2635 if not is_committing and uncovered_files:
2623 fake_db.reviewers_for(set(['foo']), 2636 fake_db.reviewers_for(set(['foo']),
2624 change.author_email).AndReturn(change.author_email) 2637 change.author_email).AndReturn(change.author_email)
2625 2638
2626 self.mox.ReplayAll() 2639 self.mox.ReplayAll()
2627 output = presubmit.PresubmitOutput() 2640 output = presubmit.PresubmitOutput()
(...skipping 12 matching lines...) Expand all
2640 dry_run=True, 2653 dry_run=True,
2641 rietveld_response=response, 2654 rietveld_response=response,
2642 reviewers=set(["ben@example.com"]), 2655 reviewers=set(["ben@example.com"]),
2643 expected_output='This is a dry run, skipping OWNERS check\n') 2656 expected_output='This is a dry run, skipping OWNERS check\n')
2644 2657
2645 self.AssertOwnersWorks(approvers=set(['ben@example.com']), 2658 self.AssertOwnersWorks(approvers=set(['ben@example.com']),
2646 is_committing=False, 2659 is_committing=False,
2647 rietveld_response=response, 2660 rietveld_response=response,
2648 expected_output='') 2661 expected_output='')
2649 2662
2663 def testCannedCheckOwners_Approved_Gerrit(self):
2664 response = {
2665 "owner": {"email": "john@example.com"},
2666 "labels": {"Code-Review": {
2667 u'all': [
2668 {
2669 u'email': u'john@example.com', # self +1 :)
2670 u'value': 1
2671 },
2672 {
2673 u'email': u'ben@example.com',
2674 u'value': 2
2675 },
2676 ],
2677 u'approved': {u'email': u'ben@example.org'},
2678 u'default_value': 0,
2679 u'values': {u' 0': u'No score',
2680 u'+1': u'Looks good to me, but someone else must approve',
2681 u'+2': u'Looks good to me, approved',
2682 u'-1': u"I would prefer that you didn't submit this",
2683 u'-2': u'Do not submit'}
2684 }},
2685 }
2686 self.AssertOwnersWorks(approvers=set(['ben@example.com']),
2687 gerrit_response=response,
2688 is_committing=True,
2689 expected_output='')
2690
2691 self.AssertOwnersWorks(approvers=set(['ben@example.com']),
2692 is_committing=False,
2693 gerrit_response=response,
2694 expected_output='')
2695
2650 def testCannedCheckOwners_Approved(self): 2696 def testCannedCheckOwners_Approved(self):
2651 response = { 2697 response = {
2652 "owner_email": "john@example.com", 2698 "owner_email": "john@example.com",
2653 "messages": [ 2699 "messages": [
2654 { 2700 {
2655 "sender": "ben@example.com", "text": "foo", "approval": True, 2701 "sender": "ben@example.com", "text": "foo", "approval": True,
2656 }, 2702 },
2657 ], 2703 ],
2658 "reviewers": ["ben@example.com"], 2704 "reviewers": ["ben@example.com"],
2659 } 2705 }
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
2886 owners_check=False) 2932 owners_check=False)
2887 self.assertEqual(2, len(results)) 2933 self.assertEqual(2, len(results))
2888 self.assertEqual( 2934 self.assertEqual(
2889 'Found line ending with white spaces in:', results[0]._message) 2935 'Found line ending with white spaces in:', results[0]._message)
2890 self.checkstdout('') 2936 self.checkstdout('')
2891 2937
2892 2938
2893 if __name__ == '__main__': 2939 if __name__ == '__main__':
2894 import unittest 2940 import unittest
2895 unittest.main() 2941 unittest.main()
OLDNEW
« no previous file with comments | « presubmit_support.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698