Chromium Code Reviews| 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 |