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

Side by Side Diff: recipe_engine/unittests/fetch_test.py

Issue 2372753002: Cleanup fetch, fix missing network flake instances (Closed)
Patch Set: Unit test for bug failure case. Created 4 years, 2 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/fetch.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 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 base64 6 import base64
7 import io 7 import io
8 import json 8 import json
9 import os 9 import os
10 import sys 10 import sys
11 import unittest 11 import unittest
12 import time 12 import time
13 13
14 import test_env 14 import test_env
15 15
16 import mock 16 import mock
17 import subprocess42 17 import subprocess42
18 18
19 from recipe_engine import fetch 19 from recipe_engine import fetch
20 from recipe_engine import requests_ssl 20 from recipe_engine import requests_ssl
21 21
22 22
23 class TestGit(unittest.TestCase): 23 class TestGit(unittest.TestCase):
24 @mock.patch('recipe_engine.fetch._run_git') 24
25 def test_fresh_clone(self, run_git): 25 def setUp(self):
26 self._patchers = [
27 mock.patch('logging.warning'),
28 mock.patch('logging.exception'),
29 mock.patch('recipe_engine.fetch.GitBackend.Git._resolve_git',
30 return_value='GIT'),
31 ]
32 for p in self._patchers:
33 p.start()
34
35 def tearDown(self):
36 for p in reversed(self._patchers):
37 p.stop()
38
39 @mock.patch('recipe_engine.fetch.GitBackend.Git._execute')
40 def test_fresh_clone(self, git):
26 fetch.GitBackend().checkout( 41 fetch.GitBackend().checkout(
27 'repo', 'revision', 'dir', allow_fetch=True) 42 'repo', 'revision', 'dir', allow_fetch=True)
28 run_git.assert_has_calls([ 43 git.assert_has_calls([
29 mock.call(None, 'clone', '-q', 'repo', 'dir'), 44 mock.call('GIT', 'clone', '-q', 'repo', 'dir'),
30 mock.call('dir', 'config', 'remote.origin.url', 'repo'), 45 mock.call('GIT', '-C', 'dir', 'config', 'remote.origin.url', 'repo'),
31 mock.call('dir', 'rev-parse', '-q', '--verify', 'revision^{commit}'), 46 mock.call('GIT', '-C', 'dir', 'rev-parse', '-q', '--verify',
32 mock.call('dir', 'reset', '-q', '--hard', 'revision'), 47 'revision^{commit}'),
48 mock.call('GIT', '-C', 'dir', 'reset', '-q', '--hard', 'revision'),
49 ])
50
51 @mock.patch('time.sleep')
52 @mock.patch('os.path.isdir')
53 @mock.patch('recipe_engine.fetch.GitBackend.Git._execute')
54 def test_fresh_clone_retries(self, git, isdir, sleep):
55 isdir.return_value = False
56
57 clone_fails = []
58 def fail_four_clones(*args):
59 if 'clone' in args and len(clone_fails) < 4:
60 clone_fails.append(True)
61 raise subprocess42.CalledProcessError(1, args)
62 return None
63 git.side_effect = fail_four_clones
64
65 fetch.GitBackend().checkout(
66 'repo', 'revision', 'dir', allow_fetch=True)
67 git.assert_has_calls([
68 mock.call('GIT', 'clone', '-q', 'repo', 'dir')] * 5 + [
69 mock.call('GIT', '-C', 'dir', 'config', 'remote.origin.url', 'repo'),
70 mock.call('GIT', '-C', 'dir', 'rev-parse', '-q', '--verify',
71 'revision^{commit}'),
72 mock.call('GIT', '-C', 'dir', 'reset', '-q', '--hard', 'revision'),
33 ]) 73 ])
34 74
35 @mock.patch('os.path.isdir') 75 @mock.patch('os.path.isdir')
36 @mock.patch('recipe_engine.fetch._run_git') 76 @mock.patch('recipe_engine.fetch.GitBackend.Git._execute')
37 def test_existing_checkout(self, run_git, isdir): 77 def test_existing_checkout(self, git, isdir):
38 isdir.return_value = True 78 isdir.return_value = True
39 fetch.GitBackend().checkout( 79 fetch.GitBackend().checkout(
40 'repo', 'revision', 'dir', allow_fetch=True) 80 'repo', 'revision', 'dir', allow_fetch=True)
41 isdir.assert_has_calls([ 81 isdir.assert_has_calls([
42 mock.call('dir'), 82 mock.call('dir'),
43 mock.call('dir/.git'), 83 mock.call('dir/.git'),
44 ]) 84 ])
45 run_git.assert_has_calls([ 85 git.assert_has_calls([
46 mock.call('dir', 'config', 'remote.origin.url', 'repo'), 86 mock.call('GIT', '-C', 'dir', 'config', 'remote.origin.url', 'repo'),
47 mock.call('dir', 'rev-parse', '-q', '--verify', 'revision^{commit}'), 87 mock.call('GIT', '-C', 'dir', 'rev-parse', '-q', '--verify',
48 mock.call('dir', 'reset', '-q', '--hard', 'revision'), 88 'revision^{commit}'),
89 mock.call('GIT', '-C', 'dir', 'reset', '-q', '--hard', 'revision'),
49 ]) 90 ])
50 91
51 @mock.patch('recipe_engine.fetch._run_git') 92 @mock.patch('recipe_engine.fetch.GitBackend.Git._execute')
52 def test_clone_not_allowed(self, run_git): 93 def test_clone_not_allowed(self, git):
53 with self.assertRaises(fetch.FetchNotAllowedError): 94 with self.assertRaises(fetch.FetchNotAllowedError):
54 fetch.GitBackend().checkout( 95 fetch.GitBackend().checkout(
55 'repo', 'revision', 'dir', allow_fetch=False) 96 'repo', 'revision', 'dir', allow_fetch=False)
56 97
57 @mock.patch('os.path.isdir') 98 @mock.patch('os.path.isdir')
58 @mock.patch('recipe_engine.fetch._run_git') 99 @mock.patch('recipe_engine.fetch.GitBackend.Git._execute')
59 def test_unclean_filesystem(self, run_git, isdir): 100 def test_unclean_filesystem(self, git, isdir):
60 isdir.side_effect = [True, False] 101 isdir.side_effect = [True, False]
61 with self.assertRaises(fetch.UncleanFilesystemError): 102 with self.assertRaises(fetch.UncleanFilesystemError):
62 fetch.GitBackend().checkout( 103 fetch.GitBackend().checkout(
63 'repo', 'revision', 'dir', allow_fetch=False) 104 'repo', 'revision', 'dir', allow_fetch=False)
64 isdir.assert_has_calls([ 105 isdir.assert_has_calls([
65 mock.call('dir'), 106 mock.call('dir'),
66 mock.call('dir/.git'), 107 mock.call('dir/.git'),
67 ]) 108 ])
68 109
69 @mock.patch('os.path.isdir') 110 @mock.patch('os.path.isdir')
70 @mock.patch('recipe_engine.fetch._run_git') 111 @mock.patch('recipe_engine.fetch.GitBackend.Git._execute')
71 def test_origin_mismatch(self, run_git, isdir): 112 def test_origin_mismatch(self, git, isdir):
72 run_git.return_value = 'not-repo' 113 git.return_value = 'not-repo'
73 isdir.return_value = True 114 isdir.return_value = True
74 115
75 # This should not raise UncleanFilesystemError, but instead 116 # This should not raise UncleanFilesystemError, but instead
76 # set the right origin automatically. 117 # set the right origin automatically.
77 fetch.GitBackend().checkout( 118 fetch.GitBackend().checkout(
78 'repo', 'revision', 'dir', allow_fetch=False) 119 'repo', 'revision', 'dir', allow_fetch=False)
79 120
80 isdir.assert_has_calls([ 121 isdir.assert_has_calls([
81 mock.call('dir'), 122 mock.call('dir'),
82 mock.call('dir/.git'), 123 mock.call('dir/.git'),
83 ]) 124 ])
84 run_git.assert_has_calls([ 125 git.assert_has_calls([
85 mock.call('dir', 'config', 'remote.origin.url', 'repo'), 126 mock.call('GIT', '-C', 'dir', 'config', 'remote.origin.url', 'repo'),
86 ]) 127 ])
87 128
88 @mock.patch('os.path.isdir') 129 @mock.patch('os.path.isdir')
89 @mock.patch('recipe_engine.fetch._run_git') 130 @mock.patch('recipe_engine.fetch.GitBackend.Git._execute')
90 def test_rev_parse_fail(self, run_git, isdir): 131 def test_rev_parse_fail(self, git, isdir):
91 run_git.side_effect = [ 132 git.side_effect = [
92 None, 133 None,
93 subprocess42.CalledProcessError(1, ['fakecmd']), 134 subprocess42.CalledProcessError(1, ['fakecmd']),
94 None, 135 None,
95 None, 136 None,
96 ] 137 ]
97 isdir.return_value = True 138 isdir.return_value = True
98 fetch.GitBackend().checkout( 139 fetch.GitBackend().checkout(
99 'repo', 'revision', 'dir', allow_fetch=True) 140 'repo', 'revision', 'dir', allow_fetch=True)
100 isdir.assert_has_calls([ 141 isdir.assert_has_calls([
101 mock.call('dir'), 142 mock.call('dir'),
102 mock.call('dir/.git'), 143 mock.call('dir/.git'),
103 ]) 144 ])
104 run_git.assert_has_calls([ 145 git.assert_has_calls([
105 mock.call('dir', 'config', 'remote.origin.url', 'repo'), 146 mock.call('GIT', '-C', 'dir', 'config', 'remote.origin.url', 'repo'),
106 mock.call('dir', 'rev-parse', '-q', '--verify', 'revision^{commit}'), 147 mock.call('GIT', '-C', 'dir', 'rev-parse', '-q', '--verify',
107 mock.call('dir', 'fetch'), 148 'revision^{commit}'),
108 mock.call('dir', 'reset', '-q', '--hard', 'revision'), 149 mock.call('GIT', '-C', 'dir', 'fetch'),
150 mock.call('GIT', '-C', 'dir', 'reset', '-q', '--hard', 'revision'),
109 ]) 151 ])
110 152
111 @mock.patch('os.path.isdir') 153 @mock.patch('os.path.isdir')
112 @mock.patch('recipe_engine.fetch._run_git') 154 @mock.patch('recipe_engine.fetch.GitBackend.Git._execute')
113 def test_rev_parse_fetch_not_allowed(self, run_git, isdir): 155 def test_rev_parse_fetch_not_allowed(self, git, isdir):
114 run_git.side_effect = [ 156 git.side_effect = [
115 None, 157 None,
116 subprocess42.CalledProcessError(1, ['fakecmd']), 158 subprocess42.CalledProcessError(1, ['fakecmd']),
117 ] 159 ]
118 isdir.return_value = True 160 isdir.return_value = True
119 with self.assertRaises(fetch.FetchNotAllowedError): 161 with self.assertRaises(fetch.FetchNotAllowedError):
120 fetch.GitBackend().checkout( 162 fetch.GitBackend().checkout(
121 'repo', 'revision', 'dir', allow_fetch=False) 163 'repo', 'revision', 'dir', allow_fetch=False)
122 isdir.assert_has_calls([ 164 isdir.assert_has_calls([
123 mock.call('dir'), 165 mock.call('dir'),
124 mock.call('dir/.git'), 166 mock.call('dir/.git'),
125 ]) 167 ])
126 run_git.assert_has_calls([ 168 git.assert_has_calls([
127 mock.call('dir', 'config', 'remote.origin.url', 'repo'), 169 mock.call('GIT', '-C', 'dir', 'config', 'remote.origin.url', 'repo'),
128 mock.call('dir', 'rev-parse', '-q', '--verify', 'revision^{commit}'), 170 mock.call('GIT', '-C', 'dir', 'rev-parse', '-q', '--verify',
171 'revision^{commit}'),
129 ]) 172 ])
130 173
131 @mock.patch('recipe_engine.fetch._run_git') 174 @mock.patch('recipe_engine.fetch.GitBackend.Git._execute')
132 def test_commit_metadata(self, run_git): 175 def test_commit_metadata(self, git):
133 run_git.side_effect = ['author', 'message'] 176 git.side_effect = ['author', 'message']
134 result = fetch.GitBackend().commit_metadata( 177 result = fetch.GitBackend().commit_metadata(
135 'repo', 'revision', 'dir', allow_fetch=True) 178 'repo', 'revision', 'dir', allow_fetch=True)
136 self.assertEqual(result, { 179 self.assertEqual(result, {
137 'author': 'author', 180 'author': 'author',
138 'message': 'message', 181 'message': 'message',
139 }) 182 })
140 run_git.assert_has_calls([ 183 git.assert_has_calls([
141 mock.call('dir', 'show', '-s', '--pretty=%aE', 'revision'), 184 mock.call('GIT', '-C', 'dir', 'show', '-s', '--pretty=%aE', 'revision'),
142 mock.call('dir', 'show', '-s', '--pretty=%B', 'revision'), 185 mock.call('GIT', '-C', 'dir', 'show', '-s', '--pretty=%B', 'revision'),
143 ]) 186 ])
144 187
145 188
146 class TestGitiles(unittest.TestCase): 189 class TestGitiles(unittest.TestCase):
147 def setUp(self): 190 def setUp(self):
148 requests_ssl.disable_check() 191 requests_ssl.disable_check()
149 192
150 @mock.patch('__builtin__.open', mock.mock_open()) 193 @mock.patch('__builtin__.open', mock.mock_open())
151 @mock.patch('shutil.rmtree') 194 @mock.patch('shutil.rmtree')
152 @mock.patch('os.makedirs') 195 @mock.patch('os.makedirs')
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 'author': 'author', 344 'author': 'author',
302 'message': 'message', 345 'message': 'message',
303 }) 346 })
304 self.assertEqual(counts['sleeps'], 4) 347 self.assertEqual(counts['sleeps'], 4)
305 requests_get.assert_has_calls([ 348 requests_get.assert_has_calls([
306 mock.call('repo/+/revision?format=JSON'), 349 mock.call('repo/+/revision?format=JSON'),
307 ] * 5) 350 ] * 5)
308 351
309 if __name__ == '__main__': 352 if __name__ == '__main__':
310 unittest.main() 353 unittest.main()
OLDNEW
« no previous file with comments | « recipe_engine/fetch.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698