OLD | NEW |
---|---|
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2010 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 """Smoke tests for gclient.py. | 6 """Smoke tests for gclient.py. |
7 | 7 |
8 Shell out 'gclient' and run basic conformance tests. | 8 Shell out 'gclient' and run basic conformance tests. |
9 | 9 |
10 This test assumes GClientSmokeBase.URL_BASE is valid. | 10 This test assumes GClientSmokeBase.URL_BASE is valid. |
11 """ | 11 """ |
12 | 12 |
13 import logging | |
13 import os | 14 import os |
15 import pprint | |
14 import shutil | 16 import shutil |
15 import subprocess | 17 import subprocess |
16 import sys | 18 import sys |
17 import unittest | 19 import unittest |
18 | 20 |
19 from fake_repos import rmtree, FakeRepos | 21 from fake_repos import rmtree, write, FakeRepos |
22 | |
23 join = os.path.join | |
20 | 24 |
21 SHOULD_LEAK = False | 25 SHOULD_LEAK = False |
22 UNITTEST_DIR = os.path.abspath(os.path.dirname(__file__)) | 26 UNITTEST_DIR = os.path.abspath(os.path.dirname(__file__)) |
23 GCLIENT_PATH = os.path.join(os.path.dirname(UNITTEST_DIR), 'gclient') | 27 GCLIENT_PATH = join(os.path.dirname(UNITTEST_DIR), 'gclient') |
24 # all tests outputs goes there. | 28 # all tests outputs goes there. |
25 TRIAL_DIR = os.path.join(UNITTEST_DIR, '_trial') | 29 TRIAL_DIR = join(UNITTEST_DIR, '_trial') |
26 # In case you want to use another machine to create the fake repos, e.g. | 30 # In case you want to use another machine to create the fake repos, e.g. |
27 # not on Windows. | 31 # not on Windows. |
28 HOST = '127.0.0.1' | 32 HOST = '127.0.0.1' |
33 FAKE = None | |
34 | |
35 | |
36 def read_tree(tree_root): | |
37 """Returns a dict of all the files in a tree.""" | |
38 tree = {} | |
39 for root, dirs, files in os.walk(tree_root): | |
40 for d in filter(lambda x: x.startswith('.'), dirs): | |
41 dirs.remove(d) | |
42 for f in [join(root, f) for f in files if not f.startswith('.')]: | |
43 tree[f[len(tree_root) + 1:]] = open(join(root, f), 'rb').read() | |
44 return tree | |
45 | |
46 | |
47 def dict_diff(dict1, dict2): | |
48 diff = {} | |
49 for k, v in dict1.iteritems(): | |
50 if k not in dict2: | |
51 diff[k] = v | |
52 elif v != dict2[k]: | |
53 diff[k] = (v, dict2[k]) | |
54 for k, v in dict2.iteritems(): | |
55 if k not in dict1: | |
56 diff[k] = v | |
57 return diff | |
58 | |
59 | |
60 def mangle_svn_tree(*args): | |
61 result = {} | |
62 for old_root, new_root, tree in args: | |
63 for k, v in tree.iteritems(): | |
64 if not k.startswith(old_root): | |
65 continue | |
66 result[join(new_root, k[len(old_root) + 1:])] = v | |
67 return result | |
68 | |
69 | |
70 def mangle_git_tree(*args): | |
71 result = {} | |
72 for new_root, tree in args: | |
73 for k, v in tree.iteritems(): | |
74 result[join(new_root, k)] = v | |
75 return result | |
29 | 76 |
30 | 77 |
31 class GClientSmokeBase(unittest.TestCase): | 78 class GClientSmokeBase(unittest.TestCase): |
32 # This subversion repository contains a test repository. | 79 # This subversion repository contains a test repository. |
33 ROOT_DIR = os.path.join(TRIAL_DIR, 'smoke') | 80 ROOT_DIR = join(TRIAL_DIR, 'smoke') |
34 | 81 |
35 def setUp(self): | 82 def setUp(self): |
36 # Vaguely inspired by twisted. | 83 # Vaguely inspired by twisted. |
37 # Make sure it doesn't try to auto update when testing! | 84 # Make sure it doesn't try to auto update when testing! |
38 self.env = os.environ.copy() | 85 self.env = os.environ.copy() |
39 self.env['DEPOT_TOOLS_UPDATE'] = '0' | 86 self.env['DEPOT_TOOLS_UPDATE'] = '0' |
40 # Remove left overs | 87 # Remove left overs |
41 self.root_dir = os.path.join(self.ROOT_DIR, self.id()) | 88 self.root_dir = join(self.ROOT_DIR, self.id()) |
42 rmtree(self.root_dir) | 89 rmtree(self.root_dir) |
43 if not os.path.exists(self.ROOT_DIR): | 90 if not os.path.exists(self.ROOT_DIR): |
44 os.mkdir(self.ROOT_DIR) | 91 os.mkdir(self.ROOT_DIR) |
45 os.mkdir(self.root_dir) | 92 os.mkdir(self.root_dir) |
46 self.svn_base = 'svn://%s/svn/' % HOST | 93 self.svn_base = 'svn://%s/svn/' % HOST |
47 self.git_base = 'git://%s/git/' % HOST | 94 self.git_base = 'git://%s/git/' % HOST |
48 | 95 |
49 def tearDown(self): | 96 def tearDown(self): |
50 if not SHOULD_LEAK: | 97 if not SHOULD_LEAK: |
51 rmtree(self.root_dir) | 98 rmtree(self.root_dir) |
(...skipping 11 matching lines...) Expand all Loading... | |
63 def checkString(expected, result): | 110 def checkString(expected, result): |
64 if expected != result: | 111 if expected != result: |
65 while expected and result and expected[0] == result[0]: | 112 while expected and result and expected[0] == result[0]: |
66 expected = expected[1:] | 113 expected = expected[1:] |
67 result = result[1:] | 114 result = result[1:] |
68 self.assertEquals(expected, result) | 115 self.assertEquals(expected, result) |
69 checkString(expected[0], results[0]) | 116 checkString(expected[0], results[0]) |
70 checkString(expected[1], results[1]) | 117 checkString(expected[1], results[1]) |
71 self.assertEquals(expected[2], results[2]) | 118 self.assertEquals(expected[2], results[2]) |
72 | 119 |
120 def assertTree(self, tree): | |
121 actual = read_tree(self.root_dir) | |
122 diff = dict_diff(tree, actual) | |
123 if diff: | |
124 logging.debug('Actual %s\n%s' % (self.root_dir, pprint.pformat(actual))) | |
125 logging.debug('Expected\n%s' % pprint.pformat(tree)) | |
126 logging.debug('Diff\n%s' % pprint.pformat(diff)) | |
127 self.assertEquals(tree, actual) | |
128 | |
73 | 129 |
74 class GClientSmoke(GClientSmokeBase): | 130 class GClientSmoke(GClientSmokeBase): |
75 def testCommands(self): | 131 def testCommands(self): |
76 """This test is to make sure no new command was added.""" | 132 """This test is to make sure no new command was added.""" |
77 result = self.gclient(['help']) | 133 result = self.gclient(['help']) |
78 self.assertEquals(3189, len(result[0])) | 134 self.assertEquals(3189, len(result[0])) |
79 self.assertEquals(0, len(result[1])) | 135 self.assertEquals(0, len(result[1])) |
80 self.assertEquals(0, result[2]) | 136 self.assertEquals(0, result[2]) |
81 | 137 |
82 def testNotConfigured(self): | 138 def testNotConfigured(self): |
83 res = ("", "Error: client not configured; see 'gclient config'\n", 1) | 139 res = ('', 'Error: client not configured; see \'gclient config\'\n', 1) |
84 self.check(res, self.gclient(['cleanup'])) | 140 self.check(res, self.gclient(['cleanup'])) |
85 self.check(res, self.gclient(['diff'])) | 141 self.check(res, self.gclient(['diff'])) |
86 self.check(res, self.gclient(['export', 'foo'])) | 142 self.check(res, self.gclient(['export', 'foo'])) |
87 self.check(res, self.gclient(['pack'])) | 143 self.check(res, self.gclient(['pack'])) |
88 self.check(res, self.gclient(['revert'])) | 144 self.check(res, self.gclient(['revert'])) |
89 self.check(res, self.gclient(['revinfo'])) | 145 self.check(res, self.gclient(['revinfo'])) |
90 self.check(res, self.gclient(['runhooks'])) | 146 self.check(res, self.gclient(['runhooks'])) |
91 self.check(res, self.gclient(['status'])) | 147 self.check(res, self.gclient(['status'])) |
92 self.check(res, self.gclient(['sync'])) | 148 self.check(res, self.gclient(['sync'])) |
93 self.check(res, self.gclient(['update'])) | 149 self.check(res, self.gclient(['update'])) |
94 | 150 |
95 | 151 |
96 class GClientSmokeSync(GClientSmokeBase): | 152 class GClientSmokeSVN(GClientSmokeBase): |
97 """sync is the most important command. Hence test it more.""" | 153 """sync is the most important command. Hence test it more.""" |
98 def testSyncSvn(self): | 154 def testSync(self): |
99 """Test pure gclient svn checkout, example of Chromium checkout""" | 155 """Test pure gclient svn checkout, example of Chromium checkout""" |
100 self.gclient(['config', self.svn_base + 'trunk/src/']) | 156 self.gclient(['config', self.svn_base + 'trunk/src/']) |
101 results = self.gclient(['sync']) | 157 # Test unversioned checkout. |
158 results = self.gclient(['sync', '--deps', 'mac']) | |
159 logging.debug(results[0]) | |
160 self.assertEquals('', results[1]) | |
102 self.assertEquals(0, results[2]) | 161 self.assertEquals(0, results[2]) |
103 results = self.gclient(['sync', '--revision', 'a@32']) | 162 tree = mangle_svn_tree( |
163 (join('trunk', 'src'), 'src', FAKE.svn_revs[-1]), | |
164 (join('trunk', 'third_party', 'foo'), join('src', 'third_party', 'foo'), | |
165 FAKE.svn_revs[1]), | |
166 (join('trunk', 'other'), join('src', 'other'), FAKE.svn_revs[2]), | |
167 ) | |
168 self.assertTree(tree) | |
169 | |
170 # Test incremental versioned sync: sync backward. | |
171 results = self.gclient(['sync', '--revision', 'src@1', '--deps', 'mac', | |
172 '--delete_unversioned_trees']) | |
173 logging.debug(results[0]) | |
174 self.assertEquals('', results[1]) | |
175 self.assertEquals(0, results[2]) | |
176 tree = mangle_svn_tree( | |
177 (join('trunk', 'src'), 'src', FAKE.svn_revs[1]), | |
178 (join('trunk', 'third_party', 'foo'), join('src', 'third_party', 'fpp'), | |
179 FAKE.svn_revs[2]), | |
180 (join('trunk', 'other'), join('src', 'other'), FAKE.svn_revs[2]), | |
181 (join('trunk', 'third_party', 'foo'), | |
182 join('src', 'third_party', 'prout'), | |
183 FAKE.svn_revs[2]), | |
184 ) | |
185 self.assertTree(tree) | |
186 # Test incremental sync: delete-unversioned_trees isn't there. | |
187 results = self.gclient(['sync', '--deps', 'mac']) | |
188 logging.debug(results[0]) | |
189 self.assertEquals('', results[1]) | |
190 self.assertEquals(0, results[2]) | |
191 tree = mangle_svn_tree( | |
192 (join('trunk', 'src'), 'src', FAKE.svn_revs[-1]), | |
193 (join('trunk', 'third_party', 'foo'), join('src', 'third_party', 'fpp'), | |
194 FAKE.svn_revs[2]), | |
195 (join('trunk', 'third_party', 'foo'), join('src', 'third_party', 'foo'), | |
196 FAKE.svn_revs[1]), | |
197 (join('trunk', 'other'), join('src', 'other'), FAKE.svn_revs[2]), | |
198 (join('trunk', 'third_party', 'foo'), | |
199 join('src', 'third_party', 'prout'), | |
200 FAKE.svn_revs[2]), | |
201 ) | |
202 self.assertTree(tree) | |
203 | |
204 def testRevertAndStatus(self): | |
205 self.gclient(['config', self.svn_base + 'trunk/src/']) | |
206 results = self.gclient(['sync', '--deps', 'mac']) | |
207 write(join(self.root_dir, 'src', 'third_party', 'foo', 'hi'), 'Hey!') | |
208 | |
209 results = self.gclient(['status']) | |
210 out = results[0].splitlines(False) | |
211 self.assertEquals(7, len(out)) | |
212 self.assertEquals(out[0], '') | |
213 self.assertTrue(out[1].startswith('________ running \'svn status\' in \'')) | |
214 self.assertEquals(out[2], '? other') | |
215 self.assertEquals(out[3], '? third_party/foo') | |
216 self.assertEquals(out[4], '') | |
217 self.assertTrue(out[5].startswith('________ running \'svn status\' in \'')) | |
218 self.assertEquals(out[6], '? hi') | |
219 self.assertEquals('', results[1]) | |
104 self.assertEquals(0, results[2]) | 220 self.assertEquals(0, results[2]) |
105 | 221 |
106 def testSyncGit(self): | 222 results = self.gclient(['revert']) |
107 """Test pure gclient git checkout, example of Chromium OS checkout""" | 223 self.assertEquals('', results[1]) |
108 self.gclient(['config', self.git_base + 'repo_1']) | 224 self.assertEquals(0, results[2]) |
109 results = self.gclient(['sync']) | 225 tree = mangle_svn_tree( |
110 print results[0] | 226 (join('trunk', 'src'), 'src', FAKE.svn_revs[-1]), |
111 print results[1] | 227 (join('trunk', 'third_party', 'foo'), join('src', 'third_party', 'foo'), |
228 FAKE.svn_revs[1]), | |
229 (join('trunk', 'other'), join('src', 'other'), FAKE.svn_revs[2]), | |
230 ) | |
231 self.assertTree(tree) | |
232 | |
233 results = self.gclient(['status']) | |
234 out = results[0].splitlines(False) | |
235 self.assertEquals(4, len(out)) | |
236 self.assertEquals(out[0], '') | |
237 self.assertTrue(out[1].startswith('________ running \'svn status\' in \'')) | |
238 self.assertEquals(out[2], '? other') | |
239 self.assertEquals(out[3], '? third_party/foo') | |
240 self.assertEquals('', results[1]) | |
112 self.assertEquals(0, results[2]) | 241 self.assertEquals(0, results[2]) |
113 | 242 |
114 | 243 |
115 class GClientSmokeRevert(GClientSmokeBase): | 244 class GClientSmokeGIT(GClientSmokeBase): |
116 """revert is the second most important command. Hence test it more.""" | 245 def testSyncGit(self): |
117 def setUp(self): | 246 """Test pure gclient git checkout, example of Chromium OS checkout""" |
118 GClientSmokeBase.setUp(self) | 247 self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
119 self.gclient(['config', self.URL_BASE]) | 248 # Test unversioned checkout. |
249 results = self.gclient(['sync', '--deps', 'mac']) | |
yaar1
2010/05/26 01:37:24
Is this only going to work on Mac?
M-A Ruel
2010/05/26 01:56:02
No but I'm enforcing the platform so the test beha
| |
250 logging.debug(results[0]) | |
251 self.assertTrue(results[1].startswith('Switched to a new branch \'')) | |
252 self.assertEquals(0, results[2]) | |
253 tree = mangle_git_tree( | |
254 ('src', FAKE.git_hashes['repo_1'][1][1]), | |
255 (join('src', 'repo2'), FAKE.git_hashes['repo_2'][0][1]), | |
256 (join('src', 'repo2', 'repo_renamed'), FAKE.git_hashes['repo_3'][1][1]), | |
257 ) | |
258 self.assertTree(tree) | |
259 | |
260 # Test incremental versioned sync: sync backward. | |
261 results = self.gclient(['sync', '--revision', | |
262 'src@' + FAKE.git_hashes['repo_1'][0][0], | |
263 '--deps', 'mac', '--delete_unversioned_trees']) | |
264 logging.debug(results[0]) | |
265 self.assertEquals('', results[1]) | |
266 self.assertEquals(0, results[2]) | |
267 tree = mangle_git_tree( | |
268 ('src', FAKE.git_hashes['repo_1'][0][1]), | |
269 (join('src', 'repo2'), FAKE.git_hashes['repo_2'][1][1]), | |
270 (join('src', 'repo2', 'repo3'), FAKE.git_hashes['repo_3'][1][1]), | |
271 (join('src', 'repo4'), FAKE.git_hashes['repo_4'][1][1]), | |
272 ) | |
273 self.assertTree(tree) | |
274 # Test incremental sync: delete-unversioned_trees isn't there. | |
275 results = self.gclient(['sync', '--deps', 'mac']) | |
276 logging.debug(results[0]) | |
277 self.assertEquals('', results[1]) | |
278 self.assertEquals(0, results[2]) | |
279 tree = mangle_git_tree( | |
280 ('src', FAKE.git_hashes['repo_1'][1][1]), | |
281 (join('src', 'repo2'), FAKE.git_hashes['repo_2'][1][1]), | |
282 (join('src', 'repo2', 'repo3'), FAKE.git_hashes['repo_3'][1][1]), | |
283 (join('src', 'repo2', 'repo_renamed'), FAKE.git_hashes['repo_3'][1][1]), | |
284 (join('src', 'repo4'), FAKE.git_hashes['repo_4'][1][1]), | |
285 ) | |
286 self.assertTree(tree) | |
287 | |
288 def testRevertAndStatus(self): | |
289 """TODO(maruel): Remove this line once this test is fixed.""" | |
290 self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) | |
291 results = self.gclient(['sync', '--deps', 'mac']) | |
292 write(join(self.root_dir, 'src', 'repo2', 'hi'), 'Hey!') | |
293 | |
294 results = self.gclient(['status']) | |
295 out = results[0].splitlines(False) | |
296 # TODO(maruel): THIS IS WRONG. | |
297 self.assertEquals(0, len(out)) | |
298 | |
299 results = self.gclient(['revert']) | |
300 self.assertEquals('', results[1]) | |
301 self.assertEquals(0, results[2]) | |
302 tree = mangle_git_tree( | |
303 ('src', FAKE.git_hashes['repo_1'][1][1]), | |
304 (join('src', 'repo2'), FAKE.git_hashes['repo_2'][0][1]), | |
305 (join('src', 'repo2', 'repo_renamed'), FAKE.git_hashes['repo_3'][1][1]), | |
306 ) | |
307 # TODO(maruel): THIS IS WRONG. | |
308 tree[join('src', 'repo2', 'hi')] = 'Hey!' | |
309 self.assertTree(tree) | |
310 | |
311 results = self.gclient(['status']) | |
312 out = results[0].splitlines(False) | |
313 # TODO(maruel): THIS IS WRONG. | |
314 self.assertEquals(0, len(out)) | |
120 | 315 |
121 | 316 |
122 class GClientSmokeRevInfo(GClientSmokeBase): | 317 class GClientSmokeRevInfo(GClientSmokeBase): |
123 """revert is the second most important command. Hence test it more.""" | 318 """revert is the second most important command. Hence test it more.""" |
124 def setUp(self): | 319 def setUp(self): |
125 GClientSmokeBase.setUp(self) | 320 GClientSmokeBase.setUp(self) |
126 self.gclient(['config', self.URL_BASE]) | 321 self.gclient(['config', self.URL_BASE]) |
127 | 322 |
128 | 323 |
129 if __name__ == '__main__': | 324 if __name__ == '__main__': |
130 fake = FakeRepos(TRIAL_DIR, SHOULD_LEAK, True) | 325 if '-v' in sys.argv: |
326 logging.basicConfig(level=logging.DEBUG) | |
327 if '-l' in sys.argv: | |
328 SHOULD_LEAK = True | |
329 sys.argv.remove('-l') | |
330 FAKE = FakeRepos(TRIAL_DIR, SHOULD_LEAK, True) | |
131 try: | 331 try: |
132 fake.setUp() | 332 FAKE.setUp() |
133 unittest.main() | 333 unittest.main() |
134 finally: | 334 finally: |
135 fake.tearDown() | 335 FAKE.tearDown() |
OLD | NEW |