Home | History | Annotate | Download | only in common_lib
      1 #! /usr/bin/python
      2 import logging, mox, os, shutil, tempfile, unittest, utils
      3 
      4 # This makes autotest_lib imports available.
      5 import common
      6 from autotest_lib.client.common_lib import revision_control
      7 
      8 
      9 class GitRepoManager(object):
     10     """
     11     A wrapper for GitRepo.
     12     """
     13     commit_hash = None
     14     commit_msg = None
     15     repodir = None
     16     git_repo_manager = None
     17 
     18 
     19     def __init__(self, master_repo=None):
     20         """
     21         Setup self.git_repo_manager.
     22 
     23         If a master_repo is present clone it.
     24         Otherwise create a directory in /tmp and init it.
     25 
     26         @param master_repo: GitRepo representing master.
     27         """
     28         if master_repo is None:
     29             self.repodir = tempfile.mktemp(suffix='master')
     30             self._create_git_repo(self.repodir)
     31             self.git_repo_manager = revision_control.GitRepo(
     32                                         self.repodir,
     33                                         self.repodir,
     34                                         abs_work_tree=self.repodir)
     35             self._setup_git_environment()
     36             # Create an initial commit. We really care about the common case
     37             # where there exists a commit in the upstream repo.
     38             self._edit('initial_commit_file', 'is_non_empty')
     39             self.add()
     40             self.commit('initial_commit')
     41         else:
     42             self.repodir = tempfile.mktemp(suffix='dependent')
     43             self.git_repo_manager = revision_control.GitRepo(
     44                                       self.repodir,
     45                                       master_repo.repodir,
     46                                       abs_work_tree=self.repodir)
     47             self.git_repo_manager.clone()
     48             self._setup_git_environment()
     49 
     50 
     51     def _setup_git_environment(self):
     52         """
     53         Mock out basic git environment to keep tests deterministic.
     54         """
     55         # Set user and email for the test git checkout.
     56         self.git_repo_manager.gitcmd('config user.name Unittests')
     57         self.git_repo_manager.gitcmd('config user.email utests (at] chromium.org')
     58 
     59 
     60     def _edit(self, filename='foo', msg='bar'):
     61         """
     62         Write msg into a file in the repodir.
     63 
     64         @param filename: Name of the file in current repo.
     65                 If none exists one will be created.
     66         @param msg: A message to write into the file.
     67         """
     68         local_file_name = os.path.join(self.git_repo_manager.repodir,
     69                                        filename)
     70         with open(local_file_name, 'w') as f:
     71             f.write(msg)
     72 
     73 
     74     def _create_git_repo(self, repodir):
     75         """
     76         Init a new git repository.
     77 
     78         @param repodir: directory for repo.
     79         """
     80         logging.info('initializing git repo in: %s', repodir)
     81         gitcmd = 'git init %s' % repodir
     82         rv = utils.run(gitcmd)
     83         if rv.exit_status != 0:
     84             logging.error(rv.stderr)
     85             raise revision_control.revision_control.GitError(gitcmd + 'failed')
     86 
     87 
     88     def add(self):
     89         """
     90         Add all unadded files in repodir to repo.
     91         """
     92         rv = self.git_repo_manager.gitcmd('add .')
     93         if rv.exit_status != 0:
     94             logging.error(rv.stderr)
     95             raise revision_control.GitError('Unable to add files to repo', rv)
     96 
     97 
     98     def commit(self, msg='default'):
     99         """
    100         Commit changes to repo with the supplied commit msg.
    101         Also updates commit_hash with the hash for this commit.
    102 
    103         @param msg: A message that goes with the commit.
    104         """
    105         self.git_repo_manager.commit(msg)
    106         self.commit_hash = self.git_repo_manager.get_latest_commit_hash()
    107 
    108 
    109     def get_master_tot(self):
    110         """
    111         Get everything from masters TOT squashing local changes.
    112         If the dependent repo is empty pull from master.
    113         """
    114         self.git_repo_manager.reinit_repo_at('master')
    115         self.commit_hash = self.git_repo_manager.get_latest_commit_hash()
    116 
    117 
    118 class RevisionControlUnittest(mox.MoxTestBase):
    119     """
    120     A unittest to exercise build_externals.py's usage
    121     of revision_control.py's Git wrappers.
    122     """
    123     master_repo=None
    124     dependent_repo=None
    125 
    126     def setUp(self):
    127         """
    128         Create a master repo and clone it into a dependent repo.
    129         """
    130         super(RevisionControlUnittest, self).setUp()
    131         self.master_repo = GitRepoManager()
    132         self.dependent_repo = GitRepoManager(self.master_repo)
    133 
    134 
    135     def tearDown(self):
    136         """
    137         Delete temporary directories.
    138         """
    139         shutil.rmtree(self.master_repo.repodir)
    140         shutil.rmtree(self.dependent_repo.repodir)
    141         super(RevisionControlUnittest, self).tearDown()
    142 
    143 
    144     def testCommit(self):
    145         """
    146         Test add, commit, pull, clone.
    147         """
    148         self.master_repo._edit()
    149         self.master_repo.add()
    150         self.master_repo.commit()
    151         self.dependent_repo.get_master_tot()
    152         self.assertEquals(self.dependent_repo.commit_hash,
    153             self.master_repo.commit_hash,
    154             msg=(("hashes don't match after clone, master and dependent repo"
    155                   "out of sync: %r != %r") %
    156                   (self.dependent_repo.commit_hash,
    157                    self.master_repo.commit_hash)))
    158 
    159         self.master_repo._edit(msg='foobar')
    160         self.master_repo.commit()
    161         self.dependent_repo.get_master_tot()
    162         self.assertEquals(self.dependent_repo.commit_hash,
    163             self.master_repo.commit_hash,
    164             msg=(("hashes don't match after pull, master and dependent repo"
    165                   "out of sync: %r != %r") %
    166                   (self.dependent_repo.commit_hash,
    167                    self.master_repo.commit_hash)))
    168 
    169 
    170     def testGitUrlClone(self):
    171         """
    172         Test that git clone raises a ValueError if giturl is unset.
    173         """
    174         self.dependent_repo.git_repo_manager._giturl = None
    175         self.assertRaises(ValueError,
    176                           self.dependent_repo.git_repo_manager.clone)
    177 
    178 
    179     def testGitUrlPull(self):
    180         """
    181         Test that git pull raises a ValueError if giturl is unset.
    182         """
    183         self.dependent_repo.git_repo_manager._giturl = None
    184         self.assertRaises(ValueError,
    185                           self.dependent_repo.git_repo_manager.pull)
    186 
    187 
    188     def testGitUrlFetch(self):
    189         """
    190         Test that git fetch raises a ValueError if giturl is unset.
    191         """
    192         self.dependent_repo.git_repo_manager._giturl = None
    193         self.assertRaises(ValueError,
    194                           self.dependent_repo.git_repo_manager.fetch_remote)
    195 
    196 
    197 if __name__ == '__main__':
    198   unittest.main()
    199