| OLD | NEW |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import atexit | 5 import atexit |
| 6 import collections | 6 import collections |
| 7 import copy | 7 import copy |
| 8 import datetime | 8 import datetime |
| 9 import hashlib | 9 import hashlib |
| 10 import os | 10 import os |
| 11 import shutil | 11 import shutil |
| 12 import subprocess | 12 import subprocess |
| 13 import sys |
| 13 import tempfile | 14 import tempfile |
| 14 import unittest | 15 import unittest |
| 15 | 16 |
| 17 from cStringIO import StringIO |
| 18 |
| 16 | 19 |
| 17 def git_hash_data(data, typ='blob'): | 20 def git_hash_data(data, typ='blob'): |
| 18 """Calculate the git-style SHA1 for some data. | 21 """Calculate the git-style SHA1 for some data. |
| 19 | 22 |
| 20 Only supports 'blob' type data at the moment. | 23 Only supports 'blob' type data at the moment. |
| 21 """ | 24 """ |
| 22 assert typ == 'blob', 'Only support blobs for now' | 25 assert typ == 'blob', 'Only support blobs for now' |
| 23 return hashlib.sha1('blob %s\0%s' % (len(data), data)).hexdigest() | 26 return hashlib.sha1('blob %s\0%s' % (len(data), data)).hexdigest() |
| 24 | 27 |
| 25 | 28 |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 """ | 254 """ |
| 252 self.repo_path = tempfile.mkdtemp(dir=self.BASE_TEMP_DIR) | 255 self.repo_path = tempfile.mkdtemp(dir=self.BASE_TEMP_DIR) |
| 253 self.commit_map = {} | 256 self.commit_map = {} |
| 254 self._date = datetime.datetime(1970, 1, 1) | 257 self._date = datetime.datetime(1970, 1, 1) |
| 255 | 258 |
| 256 self.git('init') | 259 self.git('init') |
| 257 for commit in schema.walk(): | 260 for commit in schema.walk(): |
| 258 self._add_schema_commit(commit, schema.data_for(commit.name)) | 261 self._add_schema_commit(commit, schema.data_for(commit.name)) |
| 259 self.last_commit = self[commit.name] | 262 self.last_commit = self[commit.name] |
| 260 if schema.master: | 263 if schema.master: |
| 261 self.git('update-ref', 'master', self[schema.master]) | 264 self.git('update-ref', 'refs/heads/master', self[schema.master]) |
| 262 | 265 |
| 263 def __getitem__(self, commit_name): | 266 def __getitem__(self, commit_name): |
| 264 """Gets the hash of a commit by its schema name. | 267 """Gets the hash of a commit by its schema name. |
| 265 | 268 |
| 266 >>> r = GitRepo(GitRepoSchema('A B C')) | 269 >>> r = GitRepo(GitRepoSchema('A B C')) |
| 267 >>> r['B'] | 270 >>> r['B'] |
| 268 '7381febe1da03b09da47f009963ab7998a974935' | 271 '7381febe1da03b09da47f009963ab7998a974935' |
| 269 """ | 272 """ |
| 270 return self.commit_map[commit_name] | 273 return self.commit_map[commit_name] |
| 271 | 274 |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 347 """Run a python function with the given args and kwargs with the cwd set to | 350 """Run a python function with the given args and kwargs with the cwd set to |
| 348 the git repo.""" | 351 the git repo.""" |
| 349 assert self.repo_path is not None | 352 assert self.repo_path is not None |
| 350 curdir = os.getcwd() | 353 curdir = os.getcwd() |
| 351 try: | 354 try: |
| 352 os.chdir(self.repo_path) | 355 os.chdir(self.repo_path) |
| 353 return fn(*args, **kwargs) | 356 return fn(*args, **kwargs) |
| 354 finally: | 357 finally: |
| 355 os.chdir(curdir) | 358 os.chdir(curdir) |
| 356 | 359 |
| 360 def capture_stdio(self, fn, *args, **kwargs): |
| 361 """Run a python function with the given args and kwargs with the cwd set to |
| 362 the git repo. |
| 363 |
| 364 Returns the (stdout, stderr) of whatever ran, instead of the what |fn| |
| 365 returned. |
| 366 """ |
| 367 stdout = sys.stdout |
| 368 stderr = sys.stderr |
| 369 try: |
| 370 sys.stdout = StringIO() |
| 371 sys.stderr = StringIO() |
| 372 self.run(fn, *args, **kwargs) |
| 373 return sys.stdout.getvalue(), sys.stderr.getvalue() |
| 374 finally: |
| 375 sys.stdout = stdout |
| 376 sys.stderr = stderr |
| 377 |
| 357 | 378 |
| 358 class GitRepoSchemaTestBase(unittest.TestCase): | 379 class GitRepoSchemaTestBase(unittest.TestCase): |
| 359 """A TestCase with a built-in GitRepoSchema. | 380 """A TestCase with a built-in GitRepoSchema. |
| 360 | 381 |
| 361 Expects a class variable REPO to be a GitRepoSchema string in the form | 382 Expects a class variable REPO_SCHEMA to be a GitRepoSchema string in the form |
| 362 described by that class. | 383 described by that class. |
| 363 | 384 |
| 364 You may also set class variables in the form COMMIT_%(commit_name)s, which | 385 You may also set class variables in the form COMMIT_%(commit_name)s, which |
| 365 provide the content for the given commit_name commits. | 386 provide the content for the given commit_name commits. |
| 366 | 387 |
| 367 You probably will end up using either GitRepoReadOnlyTestBase or | 388 You probably will end up using either GitRepoReadOnlyTestBase or |
| 368 GitRepoReadWriteTestBase for real tests. | 389 GitRepoReadWriteTestBase for real tests. |
| 369 """ | 390 """ |
| 370 REPO = None | 391 REPO_SCHEMA = None |
| 371 | 392 |
| 372 @classmethod | 393 @classmethod |
| 373 def getRepoContent(cls, commit): | 394 def getRepoContent(cls, commit): |
| 374 return getattr(cls, 'COMMIT_%s' % commit, None) | 395 return getattr(cls, 'COMMIT_%s' % commit, None) |
| 375 | 396 |
| 376 @classmethod | 397 @classmethod |
| 377 def setUpClass(cls): | 398 def setUpClass(cls): |
| 378 super(GitRepoSchemaTestBase, cls).setUpClass() | 399 super(GitRepoSchemaTestBase, cls).setUpClass() |
| 379 assert cls.REPO is not None | 400 assert cls.REPO_SCHEMA is not None |
| 380 cls.r_schema = GitRepoSchema(cls.REPO, cls.getRepoContent) | 401 cls.r_schema = GitRepoSchema(cls.REPO_SCHEMA, cls.getRepoContent) |
| 381 | 402 |
| 382 | 403 |
| 383 class GitRepoReadOnlyTestBase(GitRepoSchemaTestBase): | 404 class GitRepoReadOnlyTestBase(GitRepoSchemaTestBase): |
| 384 """Injects a GitRepo object given the schema and content from | 405 """Injects a GitRepo object given the schema and content from |
| 385 GitRepoSchemaTestBase into TestCase classes which subclass this. | 406 GitRepoSchemaTestBase into TestCase classes which subclass this. |
| 386 | 407 |
| 387 This GitRepo will appear as self.repo, and will be deleted and recreated once | 408 This GitRepo will appear as self.repo, and will be deleted and recreated once |
| 388 for the duration of all the tests in the subclass. | 409 for the duration of all the tests in the subclass. |
| 389 """ | 410 """ |
| 390 REPO = None | 411 REPO_SCHEMA = None |
| 391 | 412 |
| 392 @classmethod | 413 @classmethod |
| 393 def setUpClass(cls): | 414 def setUpClass(cls): |
| 394 super(GitRepoReadOnlyTestBase, cls).setUpClass() | 415 super(GitRepoReadOnlyTestBase, cls).setUpClass() |
| 395 assert cls.REPO is not None | 416 assert cls.REPO_SCHEMA is not None |
| 396 cls.repo = cls.r_schema.reify() | 417 cls.repo = cls.r_schema.reify() |
| 397 | 418 |
| 398 def setUp(self): | 419 def setUp(self): |
| 399 self.repo.git('checkout', '-f', self.repo.last_commit) | 420 self.repo.git('checkout', '-f', self.repo.last_commit) |
| 400 | 421 |
| 401 @classmethod | 422 @classmethod |
| 402 def tearDownClass(cls): | 423 def tearDownClass(cls): |
| 403 cls.repo.nuke() | 424 cls.repo.nuke() |
| 404 super(GitRepoReadOnlyTestBase, cls).tearDownClass() | 425 super(GitRepoReadOnlyTestBase, cls).tearDownClass() |
| 405 | 426 |
| 406 | 427 |
| 407 class GitRepoReadWriteTestBase(GitRepoSchemaTestBase): | 428 class GitRepoReadWriteTestBase(GitRepoSchemaTestBase): |
| 408 """Injects a GitRepo object given the schema and content from | 429 """Injects a GitRepo object given the schema and content from |
| 409 GitRepoSchemaTestBase into TestCase classes which subclass this. | 430 GitRepoSchemaTestBase into TestCase classes which subclass this. |
| 410 | 431 |
| 411 This GitRepo will appear as self.repo, and will be deleted and recreated for | 432 This GitRepo will appear as self.repo, and will be deleted and recreated for |
| 412 each test function in the subclass. | 433 each test function in the subclass. |
| 413 """ | 434 """ |
| 414 REPO = None | 435 REPO_SCHEMA = None |
| 415 | 436 |
| 416 def setUp(self): | 437 def setUp(self): |
| 417 super(GitRepoReadWriteTestBase, self).setUp() | 438 super(GitRepoReadWriteTestBase, self).setUp() |
| 418 self.repo = self.r_schema.reify() | 439 self.repo = self.r_schema.reify() |
| 419 | 440 |
| 420 def tearDown(self): | 441 def tearDown(self): |
| 421 self.repo.nuke() | 442 self.repo.nuke() |
| 422 super(GitRepoReadWriteTestBase, self).tearDown() | 443 super(GitRepoReadWriteTestBase, self).tearDown() |
| OLD | NEW |