import os import random import sys import unittest import urlparse import mitogen.master if mitogen.is_master: # TODO: shouldn't be necessary. import docker DATA_DIR = os.path.join(os.path.dirname(__file__), 'data') sys.path.append(DATA_DIR) def set_debug(): import logging logging.getLogger('mitogen').setLevel(logging.DEBUG) def data_path(suffix): path = os.path.join(DATA_DIR, suffix) if path.endswith('.key'): # SSH is funny about private key permissions. os.chmod(path, 0600) return path class TestCase(unittest.TestCase): def assertRaises(self, exc, func, *args, **kwargs): """Like regular assertRaises, except return the exception that was raised. Can't use context manager because tests must run on Python2.4""" try: func(*args, **kwargs) except exc, e: return e except BaseException, e: assert 0, '%r raised %r, not %r' % (func, e, exc) assert 0, '%r did not raise %r' % (func, exc) class DockerizedSshDaemon(object): def __init__(self): self.docker = docker.from_env() self.container_name = 'mitogen-test-%08x' % (random.getrandbits(64),) self.container = self.docker.containers.run( image='d2mw/mitogen-test', detach=True, publish_all_ports=True, ) self.container.reload() self.port = (self.container.attrs['NetworkSettings']['Ports'] ['22/tcp'][0]['HostPort']) self.host = self.get_host() def get_host(self): if self.docker.api.base_url == 'http+docker://localunixsocket': return 'localhost' parsed = urlparse.urlparse(self.docker.api.base_url) return parsed.netloc.partition(':')[0] def close(self): self.container.stop() self.container.remove() class RouterMixin(object): broker_class = mitogen.master.Broker router_class = mitogen.master.Router def setUp(self): super(RouterMixin, self).setUp() self.broker = self.broker_class() self.router = self.router_class(self.broker) def tearDown(self): self.broker.shutdown() self.broker.join() super(RouterMixin, self).tearDown() class DockerMixin(RouterMixin): @classmethod def setUpClass(cls): super(DockerMixin, cls).setUpClass() cls.dockerized_ssh = DockerizedSshDaemon() @classmethod def tearDownClass(cls): cls.dockerized_ssh.close() super(DockerMixin, cls).tearDownClass() def docker_ssh(self, **kwargs): kwargs.setdefault('hostname', self.dockerized_ssh.host) kwargs.setdefault('port', self.dockerized_ssh.port) kwargs.setdefault('check_host_keys', False) return self.router.ssh(**kwargs) def docker_ssh_any(self, **kwargs): return self.docker_ssh( username='has-sudo-nopw', password='y', )