Exemple #1
0
    def start_server(self, config=None):
        '''Starts a junebug server. Stores the service to "self.service", and
        the url at "self.url"'''
        # TODO: This setup is very manual, because we don't call
        # service.startService. This must be fixed to close mirror the real
        # program with our tests.
        if config is None:
            config = yield self.create_channel_config()
        self.service = JunebugService(config)
        self.api = JunebugApi(self.service, config)
        self.service.api = self.api

        redis = yield self.get_redis()
        yield self.api.setup(redis, self.get_message_sender())

        self.config = self.api.config
        self.redis = self.api.redis
        self.inbounds = self.api.inbounds
        self.outbounds = self.api.outbounds
        self.message_sender = self.api.message_sender

        port = reactor.listenTCP(0,
                                 Site(self.api.app.resource()),
                                 interface='127.0.0.1')
        self.service._port = port
        self.addCleanup(self.stop_server)
        addr = port.getHost()
        self.url = "http://%s:%s" % (addr.host, addr.port)
Exemple #2
0
class JunebugService(MultiService, object):
    '''Base service that runs the HTTP API, and contains transports as child
    services'''
    def __init__(self, config):
        super(JunebugService, self).__init__()
        self.config = config

    @inlineCallbacks
    def startService(self):
        '''Starts the HTTP server, and returns the port object that the server
        is listening on'''
        super(JunebugService, self).startService()
        self.api = JunebugApi(self, self.config)
        yield self.api.setup()
        self._port = reactor.listenTCP(
            self.config.port, Site(self.api.app.resource()),
            interface=self.config.interface)
        log.msg(
            'Junebug is listening on %s:%s' %
            (self.config.interface, self.config.port))

    @inlineCallbacks
    def stopService(self):
        '''Stops the HTTP server.'''
        yield self.api.teardown()
        yield self._port.stopListening()
        super(JunebugService, self).stopService()
Exemple #3
0
 def startService(self):
     '''Starts the HTTP server, and returns the port object that the server
     is listening on'''
     super(JunebugService, self).startService()
     self.api = JunebugApi(self, self.config)
     yield self.api.setup()
     self._port = reactor.listenTCP(
         self.config.port, Site(self.api.app.resource()),
         interface=self.config.interface)
     log.msg(
         'Junebug is listening on %s:%s' %
         (self.config.interface, self.config.port))
Exemple #4
0
    def start_server(self, config=None):
        '''Starts a junebug server. Stores the service to "self.service", and
        the url at "self.url"'''
        # TODO: This setup is very manual, because we don't call
        # service.startService. This must be fixed to close mirror the real
        # program with our tests.
        if config is None:
            config = yield self.create_channel_config()
        self.service = JunebugService(config)
        self.api = JunebugApi(
            self.service, config)
        self.service.api = self.api

        redis = yield self.get_redis()
        yield self.api.setup(redis, self.get_message_sender())

        self.config = self.api.config
        self.redis = self.api.redis
        self.inbounds = self.api.inbounds
        self.outbounds = self.api.outbounds
        self.message_sender = self.api.message_sender

        port = reactor.listenTCP(
            0, Site(self.api.app.resource()),
            interface='127.0.0.1')
        self.service._port = port
        self.addCleanup(self.stop_server)
        addr = port.getHost()
        self.url = "http://%s:%s" % (addr.host, addr.port)
Exemple #5
0
 def startService(self):
     """Starts the HTTP server, and returns the port object that the server
     is listening on"""
     super(JunebugService, self).startService()
     self.api = JunebugApi(self, self.config)
     yield self.api.setup()
     self._port = reactor.listenTCP(self.config.port, Site(self.api.app.resource()), interface=self.config.interface)
     log.msg("Junebug is listening on %s:%s" % (self.config.interface, self.config.port))
Exemple #6
0
class JunebugService(MultiService, object):
    """Base service that runs the HTTP API, and contains transports as child
    services"""

    def __init__(self, config):
        super(JunebugService, self).__init__()
        self.config = config

    @inlineCallbacks
    def startService(self):
        """Starts the HTTP server, and returns the port object that the server
        is listening on"""
        super(JunebugService, self).startService()
        self.api = JunebugApi(self, self.config)
        yield self.api.setup()
        self._port = reactor.listenTCP(self.config.port, Site(self.api.app.resource()), interface=self.config.interface)
        log.msg("Junebug is listening on %s:%s" % (self.config.interface, self.config.port))

    @inlineCallbacks
    def stopService(self):
        """Stops the HTTP server."""
        yield self.api.teardown()
        yield self._port.stopListening()
        super(JunebugService, self).stopService()
Exemple #7
0
    def start_server(self):
        '''Starts a junebug server. Stores the service to "self.service", and
        the url at "self.url"'''
        config = yield self.create_channel_config()
        self.service = JunebugService(config)
        self.api = JunebugApi(
            self.service, config)

        redis = yield self.persistencehelper.get_redis_manager()
        self.api = JunebugApi(self.service, config)
        yield self.api.setup(redis, self.get_message_sender())

        self.config = self.api.config
        self.redis = self.api.redis
        self.inbounds = self.api.inbounds
        self.outbounds = self.api.outbounds
        self.message_sender = self.api.message_sender

        port = reactor.listenTCP(
            0, Site(self.api.app.resource()),
            interface='127.0.0.1')
        self.addCleanup(port.stopListening)
        addr = port.getHost()
        self.url = "http://%s:%s" % (addr.host, addr.port)
Exemple #8
0
class JunebugTestBase(TestCase):
    '''Base test case that all junebug tests inherit from. Contains useful
    helper functions'''

    default_channel_properties = {
        'type': 'telnet',
        'config': {
            'twisted_endpoint': 'tcp:0',
        },
        'mo_url': 'http://foo.bar',
    }

    default_router_properties = {
        'type': 'testing',
        'config': {
            'test': 'pass',
        },
    }

    default_destination_properties = {
        'config': {
            'target': 'valid',
        },
    }

    default_channel_config = {
        'ttl': 60,
        'routers': {
            'testing': 'junebug.tests.helpers.TestRouter',
        }
    }

    def patch_logger(self):
        ''' Patches the logger with an in-memory logger, which is acccessable
        at "self.logging_handler".'''
        self.logging_handler = logging.handlers.MemoryHandler(100)
        logging.getLogger().addHandler(self.logging_handler)
        self.addCleanup(self._cleanup_logging_patch)

    def patch_message_rate_clock(self):
        '''Patches the message rate clock, and returns the clock'''
        clock = Clock()
        self.patch(MessageRateStore, 'get_seconds', lambda _: clock.seconds())
        return clock

    def _cleanup_logging_patch(self):
        self.logging_handler.close()
        logging.getLogger().removeHandler(self.logging_handler)

    def create_channel_properties(self, **kw):
        properties = deepcopy(self.default_channel_properties)
        config = kw.pop('config', {})
        properties['config'].update(config)
        properties.update(kw)
        return properties

    @inlineCallbacks
    def create_channel_config(self, **kw):
        self.persistencehelper = PersistenceHelper()
        yield self.persistencehelper.setup()
        self.addCleanup(self.persistencehelper.cleanup)

        config = deepcopy(self.default_channel_config)
        config.update(kw)
        channel_config = self.persistencehelper.mk_config(config)
        channel_config['redis'] = channel_config['redis_manager']
        returnValue(JunebugConfig(channel_config))

    def create_router_config(self, **kw):
        properties = deepcopy(self.default_router_properties)
        config = kw.pop('config', {})
        properties['config'].update(config)
        properties.update(kw)
        return properties

    def create_destination_config(self, **kw):
        properties = deepcopy(self.default_destination_properties)
        properties.update(kw)
        return properties

    @inlineCallbacks
    def create_channel(self,
                       service,
                       redis,
                       transport_class=None,
                       properties=default_channel_properties,
                       id=None,
                       config=None,
                       plugins=[]):
        '''Creates and starts, and saves a channel, with a
        TelnetServerTransport transport'''
        self.patch(junebug.logging_service, 'LogFile', DummyLogFile)
        if transport_class is None:
            transport_class = 'vumi.transports.telnet.TelnetServerTransport'

        properties = deepcopy(properties)
        logpath = self.mktemp()
        if config is None:
            config = yield self.create_channel_config(
                channels={properties['type']: transport_class},
                logging_path=logpath)

        channel = Channel(redis, config, properties, id=id, plugins=plugins)
        yield channel.start(self.service)

        properties['config']['transport_name'] = channel.id

        yield channel.save()
        self.addCleanup(channel.stop)
        returnValue(channel)

    @inlineCallbacks
    def create_channel_from_id(self, redis, config, id, service):
        '''Creates an existing channel given the channel id'''
        config = yield self.create_channel_config(**config)
        channel = yield Channel.from_id(redis, config, id, service)
        returnValue(channel)

    @inlineCallbacks
    def get_redis(self):
        '''Creates and returns a redis manager'''
        if hasattr(self, 'redis'):
            returnValue(self.redis)
        persistencehelper = PersistenceHelper()
        yield persistencehelper.setup()
        self.redis = yield persistencehelper.get_redis_manager()
        self.addCleanup(persistencehelper.cleanup)
        returnValue(self.redis)

    @inlineCallbacks
    def start_server(self, config=None):
        '''Starts a junebug server. Stores the service to "self.service", and
        the url at "self.url"'''
        # TODO: This setup is very manual, because we don't call
        # service.startService. This must be fixed to close mirror the real
        # program with our tests.
        if config is None:
            config = yield self.create_channel_config()
        self.service = JunebugService(config)
        self.api = JunebugApi(self.service, config)
        self.service.api = self.api

        redis = yield self.get_redis()
        yield self.api.setup(redis, self.get_message_sender())

        self.config = self.api.config
        self.redis = self.api.redis
        self.inbounds = self.api.inbounds
        self.outbounds = self.api.outbounds
        self.message_sender = self.api.message_sender

        port = reactor.listenTCP(0,
                                 Site(self.api.app.resource()),
                                 interface='127.0.0.1')
        self.service._port = port
        self.addCleanup(self.stop_server)
        addr = port.getHost()
        self.url = "http://%s:%s" % (addr.host, addr.port)

    @inlineCallbacks
    def stop_server(self):
        # TODO: This teardown is very messy, because we don't actually call
        # service.startService. This needs to be fixed in order to ensure that
        # our tests are mirroring the real program closely.
        yield self.service.stopService()
        for service in self.service:
            service.disownServiceParent()
        for service in self.service.namedServices.values():
            service.disownServiceParent()

    def get_message_sender(self):
        '''Creates a new MessageSender object, with a fake amqp client'''
        message_sender = MessageSender('amqp-spec-0-8.xml', None)
        spec = get_spec(vumi_resource_path('amqp-spec-0-8.xml'))
        client = FakeAmqpClient(spec)
        message_sender.client = client
        return message_sender

    def get_dispatched_messages(self, queue):
        '''Gets all messages that have been dispatched to the amqp broker.
        Should only be called after start_server, as it looks in the api for
        the amqp client'''
        amqp_client = self.api.message_sender.client
        return amqp_client.broker.get_messages('vumi', queue)

    def assert_was_logged(self, msg):
        self.assertTrue(
            any(msg in log.getMessage()
                for log in self.logging_handler.buffer))

    def assert_request(self, req, method=None, body=None, headers=None):
        if method is not None:
            self.assertEqual(req['request'].method, 'POST')

        if headers is not None:
            for name, values in headers.iteritems():
                self.assertEqual(
                    req['request'].requestHeaders.getRawHeaders(name), values)

        if body is not None:
            self.assertEqual(json.loads(req['body']), body)

    def assert_body_contains(self, req, **fields):
        body = json.loads(req['body'])

        self.assertEqual(
            dict((k, v) for k, v in body.iteritems() if k in fields), fields)

    def assert_log(self, log, expected):
        '''Assert that a log matches what is expected.'''
        timestamp = log.pop('timestamp')
        self.assertTrue(isinstance(timestamp, float))
        self.assertEqual(log, expected)

    def generate_status(self,
                        level=None,
                        components={},
                        inbound_message_rate=0,
                        outbound_message_rate=0,
                        submitted_event_rate=0,
                        rejected_event_rate=0,
                        delivery_succeeded_rate=0,
                        delivery_failed_rate=0,
                        delivery_pending_rate=0):
        '''Generates a status that the http API would respond with, given the
        same parameters'''
        return {
            'status': level,
            'components': components,
            'inbound_message_rate': inbound_message_rate,
            'outbound_message_rate': outbound_message_rate,
            'submitted_event_rate': submitted_event_rate,
            'rejected_event_rate': rejected_event_rate,
            'delivery_succeeded_rate': delivery_succeeded_rate,
            'delivery_failed_rate': delivery_failed_rate,
            'delivery_pending_rate': delivery_pending_rate,
        }

    def assert_status(self, status, **kwargs):
        '''Assert that the current channel status is correct'''
        self.assertEqual(status, self.generate_status(**kwargs))
Exemple #9
0
class JunebugTestBase(TestCase):
    '''Base test case that all junebug tests inherit from. Contains useful
    helper functions'''

    default_channel_properties = {
        'type': 'telnet',
        'config': {
            'twisted_endpoint': 'tcp:0',
        },
        'mo_url': 'http://foo.bar',
    }

    default_channel_config = {
        'ttl': 60,
        'amqp': {},
    }

    def patch_logger(self):
        ''' Patches the logger with an in-memory logger, which is acccessable
        at "self.logging_handler".'''
        self.logging_handler = logging.handlers.MemoryHandler(100)
        logging.getLogger().addHandler(self.logging_handler)
        self.addCleanup(self._cleanup_logging_patch)

    def patch_message_rate_clock(self):
        '''Patches the message rate clock, and returns the clock'''
        clock = Clock()
        self.patch(MessageRateStore, 'get_seconds', lambda _: clock.seconds())
        return clock

    def _cleanup_logging_patch(self):
        self.logging_handler.close()
        logging.getLogger().removeHandler(self.logging_handler)

    def create_channel_properties(self, **kw):
        properties = deepcopy(self.default_channel_properties)
        properties.update(kw)
        return properties

    @inlineCallbacks
    def create_channel_config(self, **kw):
        self.persistencehelper = PersistenceHelper()
        yield self.persistencehelper.setup()
        self.addCleanup(self.persistencehelper.cleanup)

        config = deepcopy(self.default_channel_config)
        config.update(kw)
        channel_config = self.persistencehelper.mk_config(config)
        channel_config['redis'] = channel_config['redis_manager']
        returnValue(JunebugConfig(channel_config))

    @inlineCallbacks
    def create_channel(
            self, service, redis, transport_class=None,
            properties=default_channel_properties, id=None, config=None,
            plugins=[]):
        '''Creates and starts, and saves a channel, with a
        TelnetServerTransport transport'''
        self.patch(junebug.logging_service, 'LogFile', DummyLogFile)
        if transport_class is None:
            transport_class = 'vumi.transports.telnet.TelnetServerTransport'

        properties = deepcopy(properties)
        logpath = self.mktemp()
        if config is None:
            config = yield self.create_channel_config(
                channels={
                    properties['type']: transport_class
                },
                logging_path=logpath)

        channel = Channel(
            redis, config, properties, id=id, plugins=plugins)
        yield channel.start(self.service)

        properties['config']['transport_name'] = channel.id

        yield channel.save()
        self.addCleanup(channel.stop)
        returnValue(channel)

    @inlineCallbacks
    def create_channel_from_id(self, redis, config, id, service):
        '''Creates an existing channel given the channel id'''
        config = yield self.create_channel_config(**config)
        channel = yield Channel.from_id(redis, config, id, service)
        returnValue(channel)

    @inlineCallbacks
    def get_redis(self):
        '''Creates and returns a redis manager'''
        if hasattr(self, 'redis'):
            returnValue(self.redis)
        persistencehelper = PersistenceHelper()
        yield persistencehelper.setup()
        self.redis = yield persistencehelper.get_redis_manager()
        self.addCleanup(persistencehelper.cleanup)
        returnValue(self.redis)

    @inlineCallbacks
    def start_server(self, config=None):
        '''Starts a junebug server. Stores the service to "self.service", and
        the url at "self.url"'''
        # TODO: This setup is very manual, because we don't call
        # service.startService. This must be fixed to close mirror the real
        # program with our tests.
        if config is None:
            config = yield self.create_channel_config()
        self.service = JunebugService(config)
        self.api = JunebugApi(
            self.service, config)
        self.service.api = self.api

        redis = yield self.get_redis()
        yield self.api.setup(redis, self.get_message_sender())

        self.config = self.api.config
        self.redis = self.api.redis
        self.inbounds = self.api.inbounds
        self.outbounds = self.api.outbounds
        self.message_sender = self.api.message_sender

        port = reactor.listenTCP(
            0, Site(self.api.app.resource()),
            interface='127.0.0.1')
        self.service._port = port
        self.addCleanup(self.stop_server)
        addr = port.getHost()
        self.url = "http://%s:%s" % (addr.host, addr.port)

    @inlineCallbacks
    def stop_server(self):
        # TODO: This teardown is very messy, because we don't actually call
        # service.startService. This needs to be fixed in order to ensure that
        # our tests are mirroring the real program closely.
        yield self.service.stopService()
        for service in self.service:
            service.disownServiceParent()
        for service in self.service.namedServices.values():
            service.disownServiceParent()

    def get_message_sender(self):
        '''Creates a new MessageSender object, with a fake amqp client'''
        message_sender = MessageSender('amqp-spec-0-8.xml', None)
        spec = get_spec(vumi_resource_path('amqp-spec-0-8.xml'))
        client = FakeAmqpClient(spec)
        message_sender.client = client
        return message_sender

    def get_dispatched_messages(self, queue):
        '''Gets all messages that have been dispatched to the amqp broker.
        Should only be called after start_server, as it looks in the api for
        the amqp client'''
        amqp_client = self.api.message_sender.client
        return amqp_client.broker.get_messages(
            'vumi', queue)

    def assert_was_logged(self, msg):
        self.assertTrue(any(
            msg in log.getMessage()
            for log in self.logging_handler.buffer))

    def assert_request(self, req, method=None, body=None, headers=None):
        if method is not None:
            self.assertEqual(req['request'].method, 'POST')

        if headers is not None:
            for name, values in headers.iteritems():
                self.assertEqual(
                    req['request'].requestHeaders.getRawHeaders(name),
                    values)

        if body is not None:
            self.assertEqual(json.loads(req['body']), body)

    def assert_body_contains(self, req, **fields):
        body = json.loads(req['body'])

        self.assertEqual(
            dict((k, v) for k, v in body.iteritems() if k in fields),
            fields)

    def assert_log(self, log, expected):
        '''Assert that a log matches what is expected.'''
        timestamp = log.pop('timestamp')
        self.assertTrue(isinstance(timestamp, float))
        self.assertEqual(log, expected)

    def generate_status(
            self, level=None, components={}, inbound_message_rate=0,
            outbound_message_rate=0, submitted_event_rate=0,
            rejected_event_rate=0, delivery_succeeded_rate=0,
            delivery_failed_rate=0, delivery_pending_rate=0):
        '''Generates a status that the http API would respond with, given the
        same parameters'''
        return {
            'status': level,
            'components': components,
            'inbound_message_rate': inbound_message_rate,
            'outbound_message_rate': outbound_message_rate,
            'submitted_event_rate': submitted_event_rate,
            'rejected_event_rate': rejected_event_rate,
            'delivery_succeeded_rate': delivery_succeeded_rate,
            'delivery_failed_rate': delivery_failed_rate,
            'delivery_pending_rate': delivery_pending_rate,
        }

    def assert_status(self, status, **kwargs):
        '''Assert that the current channel status is correct'''
        self.assertEqual(status, self.generate_status(**kwargs))
Exemple #10
0
class JunebugTestBase(TestCase):
    '''Base test case that all junebug tests inherit from. Contains useful
    helper functions'''

    default_channel_properties = {
        'type': 'telnet',
        'config': {
            'twisted_endpoint': 'tcp:0',
            'worker_name': 'unnamed',
        },
        'mo_url': 'http://foo.bar',
    }

    default_channel_config = {
        'ttl': 60,
        'amqp': {},
    }

    def patch_logger(self):
        ''' Patches the logger with an in-memory logger, which is acccessable
        at "self.logging_handler".'''
        self.logging_handler = logging.handlers.MemoryHandler(100)
        logging.getLogger().addHandler(self.logging_handler)
        self.addCleanup(self._cleanup_logging_patch)

    def _cleanup_logging_patch(self):
        self.logging_handler.close()
        logging.getLogger().removeHandler(self.logging_handler)

    def create_channel_properties(self, **kw):
        properties = deepcopy(self.default_channel_properties)
        properties.update(kw)
        return properties

    @inlineCallbacks
    def create_channel_config(self, **kw):
        self.persistencehelper = PersistenceHelper()
        yield self.persistencehelper.setup()
        self.addCleanup(self.persistencehelper.cleanup)

        config = deepcopy(self.default_channel_config)
        config.update(kw)
        channel_config = self.persistencehelper.mk_config(config)
        channel_config['redis'] = channel_config['redis_manager']
        returnValue(JunebugConfig(channel_config))

    @inlineCallbacks
    def create_channel(
            self, service, redis, transport_class,
            properties=default_channel_properties, id=None):
        '''Creates and starts, and saves a channel, with a
        TelnetServerTransport transport'''
        properties = deepcopy(properties)
        config = yield self.create_channel_config()
        channel = Channel(
            redis, config, properties, id=id)
        properties['config']['transport_name'] = channel.id
        yield channel.start(self.service)
        yield channel.save()
        self.addCleanup(channel.stop)
        returnValue(channel)

    @inlineCallbacks
    def create_channel_from_id(self, redis, config, id, service):
        '''Creates an existing channel given the channel id'''
        config = yield self.create_channel_config(**config)
        channel = yield Channel.from_id(redis, config, id, service)
        returnValue(channel)

    @inlineCallbacks
    def get_redis(self):
        '''Creates and returns a redis manager'''
        if hasattr(self, 'redis'):
            returnValue(self.redis)
        persistencehelper = PersistenceHelper()
        yield persistencehelper.setup()
        self.redis = yield persistencehelper.get_redis_manager()
        self.addCleanup(persistencehelper.cleanup)
        returnValue(self.redis)

    @inlineCallbacks
    def start_server(self):
        '''Starts a junebug server. Stores the service to "self.service", and
        the url at "self.url"'''
        config = yield self.create_channel_config()
        self.service = JunebugService(config)
        self.api = JunebugApi(
            self.service, config)

        redis = yield self.persistencehelper.get_redis_manager()
        self.api = JunebugApi(self.service, config)
        yield self.api.setup(redis, self.get_message_sender())

        self.config = self.api.config
        self.redis = self.api.redis
        self.inbounds = self.api.inbounds
        self.outbounds = self.api.outbounds
        self.message_sender = self.api.message_sender

        port = reactor.listenTCP(
            0, Site(self.api.app.resource()),
            interface='127.0.0.1')
        self.addCleanup(port.stopListening)
        addr = port.getHost()
        self.url = "http://%s:%s" % (addr.host, addr.port)

    def get_message_sender(self):
        '''Creates a new MessageSender object, with a fake amqp client'''
        message_sender = MessageSender('amqp-spec-0-8.xml', None)
        spec = get_spec(vumi_resource_path('amqp-spec-0-8.xml'))
        client = FakeAmqpClient(spec)
        message_sender.client = client
        return message_sender

    def get_dispatched_messages(self, queue):
        '''Gets all messages that have been dispatched to the amqp broker.
        Should only be called after start_server, as it looks in the api for
        the amqp client'''
        amqp_client = self.api.message_sender.client
        return amqp_client.broker.get_messages(
            'vumi', queue)