def setUp(self): super(SSHTestCase, self).setUp() self.disable_directory_isolation() tac_handler = SSHServerLayer.getTacHandler() self.server = SSHCodeHostingServer(self.scheme, tac_handler) self.server.start_server() self.addCleanup(self.server.stop_server) # Prevent creation of in-process sftp:// and bzr+ssh:// transports -- # such connections tend to leak threads and occasionally create # uncollectable garbage. ssh_denier = DenyingServer(['bzr+ssh://', 'sftp://']) ssh_denier.start_server() self.addCleanup(ssh_denier.stop_server) # Create a local branch with one revision tree = self.make_branch_and_tree('local') self.local_branch = tree.branch self.local_branch_path = local_path_from_url(self.local_branch.base) self.build_tree(['local/foo']) tree.add('foo') self.revid = tree.commit('Added foo')
class SSHTestCase(TestCaseWithTransport, LoomTestMixin, TestCaseWithFactory): """TestCase class that runs an SSH server as well as the app server.""" layer = SSHServerLayer scheme = None def setUp(self): super(SSHTestCase, self).setUp() self.disable_directory_isolation() tac_handler = SSHServerLayer.getTacHandler() self.server = SSHCodeHostingServer(self.scheme, tac_handler) self.server.start_server() self.addCleanup(self.server.stop_server) # Prevent creation of in-process sftp:// and bzr+ssh:// transports -- # such connections tend to leak threads and occasionally create # uncollectable garbage. ssh_denier = DenyingServer(['bzr+ssh://', 'sftp://']) ssh_denier.start_server() self.addCleanup(ssh_denier.stop_server) # Create a local branch with one revision tree = self.make_branch_and_tree('local') self.local_branch = tree.branch self.local_branch_path = local_path_from_url(self.local_branch.base) self.build_tree(['local/foo']) tree.add('foo') self.revid = tree.commit('Added foo') def __str__(self): return self.id() def getTransport(self, relpath=None): return self.server.getTransport(relpath) def assertBranchesMatch(self, local_url, remote_url): """Assert that two branches have the same last revision.""" local_revision = self.getLastRevision(local_url) remote_revision = self.getLastRevision(remote_url) self.assertEqual(local_revision, remote_revision) def _run_bzr(self, args, retcode=0): """Call run_bzr_subprocess with some common options. We always want to force the subprocess to do its ssh communication with paramiko (because OpenSSH doesn't respect the $HOME environment variable) and we want to load the plugins that are in rocketfuel (mainly so we can test the loom support). """ return self.run_bzr_subprocess( args, env_changes={ 'BZR_SSH': 'paramiko', 'BZR_PLUGIN_PATH': get_BZR_PLUGIN_PATH_for_subprocess() }, allow_plugins=True, retcode=retcode) def _run_bzr_error(self, args): """Run bzr expecting an error, returning the error message. """ output, error = self._run_bzr(args, retcode=3) for line in error.splitlines(): if line.startswith("bzr: ERROR"): return line raise AssertionError("Didn't find error line in output:\n\n%s\n" % error) def branch(self, remote_url, local_directory): """Branch from the given URL to a local directory.""" self._run_bzr(['branch', remote_url, local_directory]) def get_bzr_path(self): """See `bzrlib.tests.TestCase.get_bzr_path`. We override this to return the 'bzr' executable from sourcecode. """ return get_bzr_path() def push(self, local_directory, remote_url, extra_args=None): """Push the local branch to the given URL.""" args = ['push', '-d', local_directory, remote_url] if extra_args is not None: args.extend(extra_args) self._run_bzr(args) def assertCantPush(self, local_directory, remote_url, error_messages=()): """Check that we cannot push from 'local_directory' to 'remote_url'. In addition, if a list of messages is supplied as the error_messages argument, check that the bzr client printed one of these messages which shouldn't include the 'bzr: ERROR:' part of the message. :return: The last line of the stderr from the subprocess, which will be the 'bzr: ERROR: <repr of Exception>' line. """ error_line = self._run_bzr_error( ['push', '-d', local_directory, remote_url]) # This will be the will be the 'bzr: ERROR: <repr of Exception>' line. if not error_messages: return error_line for msg in error_messages: if error_line.startswith('bzr: ERROR: ' + msg): return error_line self.fail("Error message %r didn't match any of those supplied." % error_line) def getLastRevision(self, remote_url): """Get the last revision ID at the given URL.""" output, error = self._run_bzr(['revision-info', '-d', remote_url]) return output.split()[1] def getTransportURL(self, relpath=None, username=None): """Return the base URL for the tests.""" if relpath is None: relpath = '' return self.server.get_url(username) + relpath def getDatabaseBranch(self, personName, productName, branchName): """Look up and return the specified branch from the database.""" owner = Person.byName(personName) if productName is None: product = None else: product = Product.selectOneBy(name=productName) namespace = get_branch_namespace(owner, product) return namespace.getByName(branchName) def createBazaarBranch(self, user, product, branch, creator=None, branch_root=None): """Create a new branch in the database and push our test branch there. Used to create branches that the test user is not able to create, and might not even be able to view. """ authserver = xmlrpclib.ServerProxy( config.codehosting.authentication_endpoint) codehosting_api = xmlrpclib.ServerProxy( config.codehosting.codehosting_endpoint) if creator is None: creator_id = authserver.getUserAndSSHKeys(user)['id'] else: creator_id = authserver.getUserAndSSHKeys(creator)['id'] if branch_root is None: branch_root = self.server._mirror_root branch_id = codehosting_api.createBranch( creator_id, '/~%s/%s/%s' % (user, product, branch)) branch_url = 'file://' + os.path.abspath( os.path.join(branch_root, branch_id_to_path(branch_id))) self.push(self.local_branch_path, branch_url, ['--create-prefix']) return branch_url
class SSHTestCase(TestCaseWithTransport, LoomTestMixin, TestCaseWithFactory): """TestCase class that runs an SSH server as well as the app server.""" layer = SSHServerLayer scheme = None def setUp(self): super(SSHTestCase, self).setUp() self.disable_directory_isolation() tac_handler = SSHServerLayer.getTacHandler() self.server = SSHCodeHostingServer(self.scheme, tac_handler) self.server.start_server() self.addCleanup(self.server.stop_server) # Prevent creation of in-process sftp:// and bzr+ssh:// transports -- # such connections tend to leak threads and occasionally create # uncollectable garbage. ssh_denier = DenyingServer(['bzr+ssh://', 'sftp://']) ssh_denier.start_server() self.addCleanup(ssh_denier.stop_server) # Create a local branch with one revision tree = self.make_branch_and_tree('local') self.local_branch = tree.branch self.local_branch_path = local_path_from_url(self.local_branch.base) self.build_tree(['local/foo']) tree.add('foo') self.revid = tree.commit('Added foo') def __str__(self): return self.id() def getTransport(self, relpath=None): return self.server.getTransport(relpath) def assertBranchesMatch(self, local_url, remote_url): """Assert that two branches have the same last revision.""" local_revision = self.getLastRevision(local_url) remote_revision = self.getLastRevision(remote_url) self.assertEqual(local_revision, remote_revision) def runInChdir(self, directory, func, *args, **kwargs): old_dir = os.getcwdu() os.chdir(directory) try: return func(*args, **kwargs) finally: os.chdir(old_dir) def _run_bzr(self, args, retcode=0): """Call run_bzr_subprocess with some common options. We always want to force the subprocess to do its ssh communication with paramiko (because OpenSSH doesn't respect the $HOME environment variable) and we want to load the plugins that are in rocketfuel (mainly so we can test the loom support). """ return self.run_bzr_subprocess( args, env_changes={ 'BZR_SSH': 'paramiko', 'BZR_PLUGIN_PATH': get_BZR_PLUGIN_PATH_for_subprocess() }, allow_plugins=True, retcode=retcode) def _run_bzr_error(self, args): """Run bzr expecting an error, returning the error message. """ output, error = self._run_bzr(args, retcode=3) for line in error.splitlines(): if line.startswith("bzr: ERROR"): return line raise AssertionError( "Didn't find error line in output:\n\n%s\n" % error) def branch(self, remote_url, local_directory): """Branch from the given URL to a local directory.""" self._run_bzr(['branch', remote_url, local_directory]) def get_bzr_path(self): """See `bzrlib.tests.TestCase.get_bzr_path`. We override this to return the 'bzr' executable from sourcecode. """ return get_bzr_path() def push(self, local_directory, remote_url, extra_args=None): """Push the local branch to the given URL.""" args = ['push', '-d', local_directory, remote_url] if extra_args is not None: args.extend(extra_args) self._run_bzr(args) def assertCantPush(self, local_directory, remote_url, error_messages=()): """Check that we cannot push from 'local_directory' to 'remote_url'. In addition, if a list of messages is supplied as the error_messages argument, check that the bzr client printed one of these messages which shouldn't include the 'bzr: ERROR:' part of the message. :return: The last line of the stderr from the subprocess, which will be the 'bzr: ERROR: <repr of Exception>' line. """ error_line = self._run_bzr_error( ['push', '-d', local_directory, remote_url]) # This will be the will be the 'bzr: ERROR: <repr of Exception>' line. if not error_messages: return error_line for msg in error_messages: if error_line.startswith('bzr: ERROR: ' + msg): return error_line self.fail( "Error message %r didn't match any of those supplied." % error_line) def getLastRevision(self, remote_url): """Get the last revision ID at the given URL.""" output, error = self._run_bzr( ['revision-info', '-d', remote_url]) return output.split()[1] def getTransportURL(self, relpath=None, username=None): """Return the base URL for the tests.""" if relpath is None: relpath = '' return self.server.get_url(username) + relpath def getDatabaseBranch(self, personName, productName, branchName): """Look up and return the specified branch from the database.""" owner = Person.byName(personName) if productName is None: product = None else: product = Product.selectOneBy(name=productName) namespace = get_branch_namespace(owner, product) return namespace.getByName(branchName) def createBazaarBranch(self, user, product, branch, creator=None, branch_root=None): """Create a new branch in the database and push our test branch there. Used to create branches that the test user is not able to create, and might not even be able to view. """ authserver = xmlrpclib.ServerProxy( config.codehosting.authentication_endpoint) codehosting_api = xmlrpclib.ServerProxy( config.codehosting.codehosting_endpoint) if creator is None: creator_id = authserver.getUserAndSSHKeys(user)['id'] else: creator_id = authserver.getUserAndSSHKeys(creator)['id'] if branch_root is None: branch_root = self.server._mirror_root branch_id = codehosting_api.createBranch( creator_id, '/~%s/%s/%s' % (user, product, branch)) branch_url = 'file://' + os.path.abspath( os.path.join(branch_root, branch_id_to_path(branch_id))) self.push(self.local_branch_path, branch_url, ['--create-prefix']) return branch_url