def test_send_message(self): '''Sending a message should place the message on the queue for the channel''' properties = self.create_channel_properties() config = yield self.create_channel_config() redis = yield self.get_redis() channel = Channel(redis, config, properties, id='test-channel') yield channel.save() yield channel.start(self.service) resp = yield self.post('/channels/test-channel/messages/', { 'to': '+1234', 'content': 'foo', 'from': None }) yield self.assert_response(resp, http.OK, 'message sent', { 'to': '+1234', 'channel_id': 'test-channel', 'from': None, 'reply_to': None, 'channel_data': {}, 'content': 'foo', }, ignore=['timestamp', 'message_id']) [message] = self.get_dispatched_messages('test-channel.outbound') message_id = (yield resp.json())['result']['message_id'] self.assertEqual(message['message_id'], message_id) event_url = yield self.api.outbounds.load_event_url( 'test-channel', message['message_id']) self.assertEqual(event_url, None)
def test_delete_channel(self): config = yield self.create_channel_config() properties = self.create_channel_properties() channel = Channel(self.redis, config, properties, 'test-channel') yield channel.save() yield channel.start(self.service) self.assertTrue('test-channel' in self.service.namedServices) properties = yield self.redis.get('test-channel:properties') self.assertNotEqual(properties, None) resp = yield self.delete('/channels/test-channel') yield self.assert_response(resp, http.OK, 'channel deleted', {}) self.assertFalse('test-channel' in self.service.namedServices) properties = yield self.redis.get('test-channel:properties') self.assertEqual(properties, None) resp = yield self.delete('/channels/test-channel') yield self.assert_response( resp, http.NOT_FOUND, 'channel not found', { 'errors': [{ 'message': '', 'type': 'ChannelNotFound', }] }) self.assertFalse('test-channel' in self.service.namedServices) properties = yield self.redis.get('test-channel:properties') self.assertEqual(properties, None)
def send_message(self, request, body, channel_id): '''Send an outbound (mobile terminated) message''' if 'to' not in body and 'reply_to' not in body: raise ApiUsageError( 'Either "to" or "reply_to" must be specified') if 'to' in body and 'reply_to' in body: raise ApiUsageError( 'Only one of "to" and "reply_to" may be specified') if 'from' in body and 'reply_to' in body: raise ApiUsageError( 'Only one of "from" and "reply_to" may be specified') try: self.service.getServiceNamed(channel_id) except KeyError: raise ChannelNotFound() if 'to' in body: msg = yield Channel.send_message( channel_id, self.message_sender, self.outbounds, body) else: msg = yield Channel.send_reply_message( channel_id, self.message_sender, self.outbounds, self.inbounds, body) returnValue(response(request, 'message sent', msg))
def test_send_message_event_url(self): '''Sending a message with a specified event url should store the event url for sending events in the future''' properties = self.create_channel_properties() config = yield self.create_channel_config() redis = yield self.get_redis() channel = Channel(redis, config, properties, 'test-channel') yield channel.save() yield channel.start(self.service) resp = yield self.post('/channels/test-channel/messages/', { 'to': '+1234', 'content': 'foo', 'from': None, 'event_url': 'http://test.org'}) yield self.assert_response( resp, http.OK, 'message sent', { 'to': '+1234', 'channel_id': 'test-channel', 'from': None, 'reply_to': None, 'channel_data': {}, 'content': 'foo', }, ignore=['timestamp', 'message_id']) event_url = yield self.api.outbounds.load_event_url( 'test-channel', (yield resp.json())['result']['message_id']) self.assertEqual(event_url, 'http://test.org')
def test_send_message(self): '''Sending a message should place the message on the queue for the channel''' properties = self.create_channel_properties() config = yield self.create_channel_config() redis = yield self.get_redis() channel = Channel(redis, config, properties, 'test-channel') yield channel.save() yield channel.start(self.service) resp = yield self.post('/channels/test-channel/messages/', { 'to': '+1234', 'content': 'foo', 'from': None}) yield self.assert_response( resp, http.OK, 'message sent', { 'to': '+1234', 'channel_id': 'test-channel', 'from': None, 'reply_to': None, 'channel_data': {}, 'content': 'foo', }, ignore=['timestamp', 'message_id']) [message] = self.get_dispatched_messages('test-channel.outbound') message_id = (yield resp.json())['result']['message_id'] self.assertEqual(message['message_id'], message_id) event_url = yield self.api.outbounds.load_event_url( 'test-channel', message['message_id']) self.assertEqual(event_url, None)
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)
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)
def test_send_message_over_character_limit(self): '''If the content length is over the character limit, an error should be returned''' properties = self.create_channel_properties(character_limit=10) config = yield self.create_channel_config() redis = yield self.get_redis() channel = Channel(redis, config, properties, id='test-channel') yield channel.save() yield channel.start(self.service) resp = yield self.post('/channels/test-channel/messages/', { 'to': '+1234', 'content': 'Over the character limit.', 'from': None }) yield self.assert_response( resp, http.BAD_REQUEST, 'message too long', { 'errors': [{ 'message': "Message content u'Over the character limit.' " "is of length 25, which is greater than the character " "limit of 10", 'type': 'MessageTooLong', }], })
def test_send_message_equal_character_limit(self): '''If the content length is equal to the character limit, no errors should be returned''' content = 'Equal to the character limit.' properties = self.create_channel_properties( character_limit=len(content)) config = yield self.create_channel_config() redis = yield self.get_redis() channel = Channel(redis, config, properties, id='test-channel') yield channel.save() yield channel.start(self.service) resp = yield self.post('/channels/test-channel/messages/', { 'to': '+1234', 'content': content, 'from': None }) yield self.assert_response(resp, http.OK, 'message sent', { 'to': '+1234', 'channel_id': 'test-channel', 'from': None, 'reply_to': None, 'channel_data': {}, 'content': content, }, ignore=['timestamp', 'message_id'])
def test_send_message_event_url(self): '''Sending a message with a specified event url should store the event url for sending events in the future''' properties = self.create_channel_properties() config = yield self.create_channel_config() redis = yield self.get_redis() channel = Channel(redis, config, properties, id='test-channel') yield channel.save() yield channel.start(self.service) resp = yield self.post( '/channels/test-channel/messages/', { 'to': '+1234', 'content': 'foo', 'from': None, 'event_url': 'http://test.org' }) yield self.assert_response(resp, http.OK, 'message sent', { 'to': '+1234', 'channel_id': 'test-channel', 'from': None, 'reply_to': None, 'channel_data': {}, 'content': 'foo', }, ignore=['timestamp', 'message_id']) event_url = yield self.api.outbounds.load_event_url( 'test-channel', (yield resp.json())['result']['message_id']) self.assertEqual(event_url, 'http://test.org')
def test_delete_channel(self): config = yield self.create_channel_config() properties = self.create_channel_properties() channel = Channel(self.redis, config, properties, id='test-channel') yield channel.save() yield channel.start(self.service) self.assertTrue('test-channel' in self.service.namedServices) properties = yield self.redis.get('test-channel:properties') self.assertNotEqual(properties, None) resp = yield self.delete('/channels/test-channel') yield self.assert_response(resp, http.OK, 'channel deleted', {}) self.assertFalse('test-channel' in self.service.namedServices) properties = yield self.redis.get('test-channel:properties') self.assertEqual(properties, None) resp = yield self.delete('/channels/test-channel') yield self.assert_response( resp, http.NOT_FOUND, 'channel not found', {'errors': [{ 'message': '', 'type': 'ChannelNotFound', }]}) self.assertFalse('test-channel' in self.service.namedServices) properties = yield self.redis.get('test-channel:properties') self.assertEqual(properties, None)
def create_channel(self, request, body): '''Create a channel''' channel = Channel( self.redis, self.config, body) yield channel.save() yield channel.start(self.service) returnValue(response( request, 'channel created', (yield channel.status())))
def create_channel(self, request, body): '''Create a channel''' channel = Channel( self.redis, self.config, body, self.plugins) yield channel.start(self.service) yield channel.save() returnValue(response( request, 'channel created', (yield channel.status()), code=http.CREATED))
def create_channel(self, request, body): '''Create a channel''' if not (body.get('mo_url') or body.get('amqp_queue')): raise ApiUsageError( 'One or both of "mo_url" and "amqp_queue" must be specified') channel = Channel(self.redis, self.config, body, self.plugins) yield channel.start(self.service) yield channel.save() returnValue( response(request, 'channel created', (yield channel.status())))
def test_get_all(self): channels = yield Channel.get_all(self.redis) self.assertEqual(channels, set()) channel1 = yield self.create_channel(self.service, self.redis) channels = yield Channel.get_all(self.redis) self.assertEqual(channels, set([channel1.id])) channel2 = yield self.create_channel(self.service, self.redis) channels = yield Channel.get_all(self.redis) self.assertEqual(channels, set([channel1.id, channel2.id]))
def create_channel(self, request, body): '''Create a channel''' if not (body.get('mo_url') or body.get('amqp_queue')): raise ApiUsageError( 'One or both of "mo_url" and "amqp_queue" must be specified') channel = Channel( self.redis, self.config, body, self.plugins) yield channel.save() yield channel.start(self.service) returnValue(response( request, 'channel created', (yield channel.status())))
def test_get_all_channels(self): channels = yield Channel.get_all(self.redis) self.assertEqual(channels, set()) channel1 = yield self.create_channel( self.service, self.redis, TelnetServerTransport) channels = yield Channel.get_all(self.redis) self.assertEqual(channels, set([channel1.id])) channel2 = yield self.create_channel( self.service, self.redis, TelnetServerTransport) channels = yield Channel.get_all(self.redis) self.assertEqual(channels, set([channel1.id, channel2.id]))
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)
def test_get_channel(self): properties = self.create_channel_properties() config = yield self.create_channel_config() redis = yield self.get_redis() channel = Channel(redis, config, properties, u'test-channel') yield channel.save() yield channel.start(self.service) resp = yield self.get('/channels/test-channel') yield self.assert_response( resp, http.OK, 'channel found', conjoin(properties, { 'status': {}, 'id': 'test-channel', }))
def test_get_channel(self): properties = self.create_channel_properties() config = yield self.create_channel_config() redis = yield self.get_redis() channel = Channel(redis, config, properties, id=u'test-channel') yield channel.save() yield channel.start(self.service) resp = yield self.get('/channels/test-channel') yield self.assert_response( resp, http.OK, 'channel found', conjoin(properties, { 'status': self.generate_status(), 'id': 'test-channel', }))
def test_restart_channel(self): config = yield self.create_channel_config() properties = self.create_channel_properties() channel = Channel(self.redis, config, properties, id='test-channel') yield channel.save() yield channel.start(self.service) actions = self.record_channel_methods('start', 'stop') resp = yield self.post('/channels/test-channel/restart', None) yield self.assert_response(resp, http.OK, 'channel restarted', {}) self.assertEqual(actions, [ ('stop', u'test-channel'), ('start', u'test-channel'), ])
def send_message(self, request, body, channel_id): '''Send an outbound (mobile terminated) message''' if 'to' not in body and 'reply_to' not in body: raise ApiUsageError( 'Either "to" or "reply_to" must be specified') if 'to' in body and 'reply_to' in body: raise ApiUsageError( 'Only one of "to" and "reply_to" may be specified') if 'from' in body and 'reply_to' in body: raise ApiUsageError( 'Only one of "from" and "reply_to" may be specified') channel = yield Channel.from_id( self.redis, self.config, channel_id, self.service, self.plugins) if 'to' in body: msg = yield channel.send_message( self.message_sender, self.outbounds, body) else: msg = yield channel.send_reply_message( self.message_sender, self.outbounds, self.inbounds, body) yield self.message_rate.increment( channel_id, 'outbound', self.config.metric_window) returnValue(response(request, 'message sent', msg))
def test_transport_class_name_specified(self): config = yield self.create_channel_config(channels={'foo': 'bar.baz'}) properties = self.create_channel_properties(type='foo') channel = Channel(self.redis, config, properties) self.assertEqual( channel._transport_cls_name, 'bar.baz')
def test_transport_class_name_default(self): config = yield self.create_channel_config(channels={}) properties = self.create_channel_properties(type='telnet') channel = Channel(self.redis, config, properties) self.assertEqual( channel._transport_cls_name, 'vumi.transports.telnet.TelnetServerTransport')
def validate_router_config(cls, api, config): try: config = FromAddressRouterConfig(config) except ConfigError as e: raise InvalidRouterConfig(e.message) channel_id = str(config.channel) try: channel = yield Channel.from_id( api.redis, api.config, channel_id, api.service, api.plugins) except ChannelNotFound: raise InvalidRouterConfig( "Channel {} does not exist".format(channel_id)) if channel.has_destination: raise InvalidRouterConfig( "Channel {} already has a destination specified".format( channel_id)) # Check that no other routers are listening to this channel def check_router_channel(router): channel = router.get('config', {}).get('channel', None) if channel == channel_id: raise InvalidRouterConfig( "Router {} is already routing channel {}".format( router['id'], channel_id)) routers = yield api.router_store.get_router_list() routers = yield gatherResults([ api.router_store.get_router_config(r) for r in routers]) for router in routers: check_router_channel(router)
def setup(self, redis=None, message_sender=None): if redis is None: redis = yield TxRedisManager.from_config(self.redis_config) if message_sender is None: message_sender = MessageSender( 'amqp-spec-0-8.xml', self.amqp_config) self.redis = redis self.message_sender = message_sender self.message_sender.setServiceParent(self.service) self.inbounds = InboundMessageStore( self.redis, self.config.inbound_message_ttl) self.outbounds = OutboundMessageStore( self.redis, self.config.outbound_message_ttl) self.message_rate = MessageRateStore(self.redis) self.plugins = [] for plugin_config in self.config.plugins: cls = load_class_by_string(plugin_config['type']) plugin = cls() yield plugin.start_plugin(plugin_config, self.config) self.plugins.append(plugin) yield Channel.start_all_channels( self.redis, self.config, self.service, self.plugins)
def delete_channel(self, request, channel_id): '''Delete the channel''' channel = yield Channel.from_id(self.redis, self.config, channel_id, self.service, self.plugins) yield channel.stop() yield channel.delete() returnValue(response(request, 'channel deleted', {}))
def send_message(self, request, body, channel_id): '''Send an outbound (mobile terminated) message''' if 'to' not in body and 'reply_to' not in body: raise ApiUsageError('Either "to" or "reply_to" must be specified') if 'to' in body and 'reply_to' in body: raise ApiUsageError( 'Only one of "to" and "reply_to" may be specified') if 'from' in body and 'reply_to' in body: raise ApiUsageError( 'Only one of "from" and "reply_to" may be specified') channel = yield Channel.from_id(self.redis, self.config, channel_id, self.service, self.plugins) if 'to' in body: msg = yield channel.send_message(self.message_sender, self.outbounds, body) else: msg = yield channel.send_reply_message(self.message_sender, self.outbounds, self.inbounds, body) yield self.message_rate.increment(channel_id, 'outbound', self.config.metric_window) returnValue(response(request, 'message sent', msg))
def setup(self, redis=None, message_sender=None): if redis is None: redis = yield TxRedisManager.from_config(self.redis_config) if message_sender is None: message_sender = MessageSender('amqp-spec-0-8.xml', self.amqp_config) self.redis = redis self.message_sender = message_sender self.message_sender.setServiceParent(self.service) self.inbounds = InboundMessageStore(self.redis, self.config.inbound_message_ttl) self.outbounds = OutboundMessageStore(self.redis, self.config.outbound_message_ttl) self.message_rate = MessageRateStore(self.redis) self.plugins = [] for plugin_config in self.config.plugins: cls = load_class_by_string(plugin_config['type']) plugin = cls() yield plugin.start_plugin(plugin_config, self.config) self.plugins.append(plugin) yield Channel.start_all_channels(self.redis, self.config, self.service, self.plugins)
def test_send_message_message_rate(self): '''Sending a message should increment the message rate counter''' clock = yield self.patch_message_rate_clock() channel = Channel( (yield self.get_redis()), (yield self.create_channel_config()), self.create_channel_properties(), id='test-channel') yield channel.save() yield channel.start(self.service) yield self.post('/channels/test-channel/messages/', { 'to': '+1234', 'content': 'foo', 'from': None}) clock.advance(channel.config.metric_window) rate = yield self.api.message_rate.get_messages_per_second( 'test-channel', 'outbound', channel.config.metric_window) self.assertEqual(rate, 1.0 / channel.config.metric_window)
def test_send_reply_message_event_url(self): '''Sending a message with a specified event url should store the event url for sending events in the future''' yield self.create_channel( self.service, self.redis, TelnetServerTransport, id='channel-id') in_msg = TransportUserMessage( from_addr='+2789', to_addr='+1234', transport_name='channel-id', transport_type='_', transport_metadata={'foo': 'bar'}) yield self.api.inbounds.store_vumi_message('channel-id', in_msg) msg = yield Channel.send_reply_message( 'channel-id', self.message_sender, self.outbounds, self.inbounds, { 'reply_to': in_msg['message_id'], 'content': 'testcontent', 'event_url': 'http://test.org', }) event_url = yield self.outbounds.load_event_url( 'channel-id', msg['message_id']) self.assertEqual(event_url, 'http://test.org')
def modify_channel(self, request, body, channel_id): '''Mondify the channel configuration''' channel = yield Channel.from_id( self.redis, self.config, channel_id, self.service, self.plugins) resp = yield channel.update(body) returnValue(response( request, 'channel updated', resp))
def restart_channel(self, request, channel_id): '''Restart a channel.''' channel = yield Channel.from_id( self.redis, self.config, channel_id, self.service, self.plugins) yield channel.stop() yield channel.start(self.service) returnValue(response(request, 'channel restarted', {}))
def get_channel(self, request, channel_id): '''Return the channel configuration and a nested status object''' channel = yield Channel.from_id( self.redis, self.config, channel_id, self.service) resp = yield channel.status() returnValue(response( request, 'channel found', resp))
def get_channel(self, request, channel_id): '''Return the channel configuration and a nested status object''' channel = yield Channel.from_id( self.redis, self.config, channel_id, self.service, self.plugins) resp = yield channel.status() returnValue(response( request, 'channel found', resp))
def modify_channel(self, request, body, channel_id): '''Mondify the channel configuration''' channel = yield Channel.from_id( self.redis, self.config, channel_id, self.service) resp = yield channel.update(body) returnValue(response( request, 'channel updated', resp))
def test_send_reply_message(self): '''send_reply_message should place the correct reply message on the correct queue''' yield self.create_channel( self.service, self.redis, TelnetServerTransport, id='channel-id') in_msg = TransportUserMessage( from_addr='+2789', to_addr='+1234', transport_name='channel-id', transport_type='_', transport_metadata={'foo': 'bar'}) yield self.api.inbounds.store_vumi_message('channel-id', in_msg) msg = yield Channel.send_reply_message( 'channel-id', self.message_sender, self.outbounds, self.inbounds, { 'reply_to': in_msg['message_id'], 'content': 'testcontent', }) expected = in_msg.reply(content='testcontent') expected = conjoin(api_from_message(expected), { 'timestamp': msg['timestamp'], 'message_id': msg['message_id'] }) self.assertEqual(msg, expected) [dispatched] = self.get_dispatched_messages('channel-id.outbound') self.assertEqual(msg['message_id'], dispatched['message_id']) self.assertEqual(api_from_message(dispatched), expected)
def test_start_all_channels(self): yield Channel.start_all_channels(self.redis, self.config, self.service) channel1 = yield self.create_channel(self.service, self.redis) self.assertTrue(channel1.id in self.service.namedServices) yield channel1.stop() self.assertFalse(channel1.id in self.service.namedServices) yield Channel.start_all_channels(self.redis, self.config, self.service) self.assertTrue(channel1.id in self.service.namedServices) channel2 = yield self.create_channel(self.service, self.redis) self.assertTrue(channel2.id in self.service.namedServices) yield channel2.stop() self.assertFalse(channel2.id in self.service.namedServices) yield Channel.start_all_channels(self.redis, self.config, self.service) self.assertTrue(channel1.id in self.service.namedServices) self.assertTrue(channel2.id in self.service.namedServices)
def delete_channel(self, request, channel_id): '''Delete the channel''' channel = yield Channel.from_id( self.redis, self.config, channel_id, self.service) yield channel.stop() yield channel.delete() returnValue(response( request, 'channel deleted', {}))
def test_modify_channel_config_change(self): redis = yield self.get_redis() properties = self.create_channel_properties() config = yield self.create_channel_config() channel = Channel(redis, config, properties, 'test-channel') yield channel.save() yield channel.start(self.service) properties['config']['name'] = 'bar' resp = yield self.post('/channels/test-channel', properties) yield self.assert_response( resp, http.OK, 'channel updated', conjoin(properties, { 'status': {}, 'id': 'test-channel', }))
def test_transport_class_name_overridden(self): config = yield self.create_channel_config(channels={'foo': 'bar.baz'}, replace_channels=True) properties = self.create_channel_properties(type='telnet') channel = Channel(self.redis, config, properties) err = self.assertRaises(InvalidChannelType, getattr, channel, '_transport_cls_name') self.assertTrue(all(cls in err.message for cls in ['telnet', 'foo']))
def test_modify_channel_config_change(self): redis = yield self.get_redis() properties = self.create_channel_properties() config = yield self.create_channel_config() channel = Channel(redis, config, properties, id='test-channel') yield channel.save() yield channel.start(self.service) properties['config']['name'] = 'bar' resp = yield self.post('/channels/test-channel', properties) yield self.assert_response( resp, http.OK, 'channel updated', conjoin(properties, { 'status': self.generate_status(), 'id': 'test-channel', }))
def test_modify_channel_no_config_change(self): properties = self.create_channel_properties() config = yield self.create_channel_config() redis = yield self.get_redis() channel = Channel(redis, config, properties, 'test-channel') yield channel.save() yield channel.start(self.service) resp = yield self.post( '/channels/test-channel', {'metadata': {'foo': 'bar'}}) yield self.assert_response( resp, http.OK, 'channel updated', conjoin(properties, { 'status': {}, 'id': 'test-channel', 'metadata': {'foo': 'bar'}, }))
def get_logs(self, request, channel_id): '''Get the last N logs for a channel, sorted reverse chronologically.''' n = request.args.get('n', None) if n is not None: n = int(n[0]) channel = yield Channel.from_id( self.redis, self.config, channel_id, self.service, self.plugins) logs = yield channel.get_logs(n) returnValue(response(request, 'logs retrieved', logs))
def test_send_message_message_rate(self): '''Sending a message should increment the message rate counter''' clock = yield self.patch_message_rate_clock() channel = Channel((yield self.get_redis()), (yield self.create_channel_config()), self.create_channel_properties(), id='test-channel') yield channel.save() yield channel.start(self.service) yield self.post('/channels/test-channel/messages/', { 'to': '+1234', 'content': 'foo', 'from': None }) clock.advance(channel.config.metric_window) rate = yield self.api.message_rate.get_messages_per_second( 'test-channel', 'outbound', channel.config.metric_window) self.assertEqual(rate, 1.0 / channel.config.metric_window)
def test_send_reply_message_inbound_not_found(self): '''send_reply_message should raise an error if the inbound message is not found''' yield self.create_channel( self.service, self.redis, TelnetServerTransport, id='channel-id') self.assertFailure(Channel.send_reply_message( 'channel-id', self.message_sender, self.outbounds, self.inbounds, { 'reply_to': 'i-do-not-exist', 'content': 'testcontent', }), MessageNotFound)
def test_send_message_under_character_limit(self): '''If the content length is under the character limit, no errors should be returned''' properties = self.create_channel_properties(character_limit=100) config = yield self.create_channel_config() redis = yield self.get_redis() channel = Channel(redis, config, properties, id='test-channel') yield channel.save() yield channel.start(self.service) resp = yield self.post('/channels/test-channel/messages/', { 'to': '+1234', 'content': 'Under the character limit.', 'from': None}) yield self.assert_response( resp, http.OK, 'message sent', { 'to': '+1234', 'channel_id': 'test-channel', 'from': None, 'reply_to': None, 'channel_data': {}, 'content': 'Under the character limit.', }, ignore=['timestamp', 'message_id'])
def health_status(self, request): if self.config.rabbitmq_management_interface: def get_queues(channel_ids): gets = [] for channel_id in channel_ids: for sub in ['inbound', 'outbound', 'event']: queue_name = "%s.%s" % (channel_id, sub) get = self.rabbitmq_management_client.get_queue( self.amqp_config['vhost'], queue_name) gets.append(get) return gets def return_queue_results(results): queues = [] stuck = False for result in results: queue = result[1] if ('messages' in queue): details = { 'name': queue['name'], 'stuck': False, 'messages': queue.get('messages'), 'rate': queue['messages_details']['rate'] } if (details['messages'] > 0 and details['rate'] == 0): stuck = True details['stuck'] = True queues.append(details) status = 'queues ok' code = http.OK if stuck: status = "queues stuck" code = http.INTERNAL_SERVER_ERROR return response(request, status, queues, code=code) d = Channel.get_all(self.redis) d.addCallback(get_queues) d.addCallback(defer.DeferredList) d.addCallback(return_queue_results) return d else: return response(request, 'health ok', {})
def test_send_message_over_character_limit(self): '''If the content length is over the character limit, an error should be returned''' properties = self.create_channel_properties(character_limit=10) config = yield self.create_channel_config() redis = yield self.get_redis() channel = Channel(redis, config, properties, id='test-channel') yield channel.save() yield channel.start(self.service) resp = yield self.post('/channels/test-channel/messages/', { 'to': '+1234', 'content': 'Over the character limit.', 'from': None}) yield self.assert_response( resp, http.BAD_REQUEST, 'message too long', { 'errors': [{ 'message': "Message content u'Over the character limit.' " "is of length 25, which is greater than the character " "limit of 10", 'type': 'MessageTooLong', }], })
def test_get_channel_list(self): redis = yield self.get_redis() properties = self.create_channel_properties() config = yield self.create_channel_config() resp = yield self.get('/channels/') yield self.assert_response(resp, http.OK, 'channels listed', []) yield Channel(redis, config, properties, id=u'test-channel-1').save() resp = yield self.get('/channels/') yield self.assert_response(resp, http.OK, 'channels listed', [ u'test-channel-1', ]) yield Channel(redis, config, properties, id=u'test-channel-2').save() resp = yield self.get('/channels/') yield self.assert_response(resp, http.OK, 'channels listed', [ u'test-channel-1', u'test-channel-2', ])
def test_start_all_channels(self): yield Channel.start_all_channels( self.redis, self.config, self.service) channel1 = yield self.create_channel( self.service, self.redis) self.assertTrue(channel1.id in self.service.namedServices) yield channel1.stop() self.assertFalse(channel1.id in self.service.namedServices) yield Channel.start_all_channels( self.redis, self.config, self.service) self.assertTrue(channel1.id in self.service.namedServices) channel2 = yield self.create_channel( self.service, self.redis) self.assertTrue(channel2.id in self.service.namedServices) yield channel2.stop() self.assertFalse(channel2.id in self.service.namedServices) yield Channel.start_all_channels( self.redis, self.config, self.service) self.assertTrue(channel1.id in self.service.namedServices) self.assertTrue(channel2.id in self.service.namedServices)
def test_send_message_reply(self): '''Sending a reply message should fetch the relevant inbound message, use it to construct a reply message, and place the reply message on the queue for the channel''' channel = Channel( redis_manager=(yield self.get_redis()), config=(yield self.create_channel_config()), properties=self.create_channel_properties(), id='test-channel') yield channel.save() yield channel.start(self.service) in_msg = TransportUserMessage( from_addr='+2789', to_addr='+1234', transport_name='test-channel', transport_type='_', transport_metadata={'foo': 'bar'}) yield self.api.inbounds.store_vumi_message('test-channel', in_msg) expected = in_msg.reply(content='testcontent') expected = api_from_message(expected) resp = yield self.post('/channels/test-channel/messages/', { 'reply_to': in_msg['message_id'], 'content': 'testcontent', }) yield self.assert_response( resp, http.OK, 'message sent', omit(expected, 'timestamp', 'message_id'), ignore=['timestamp', 'message_id']) [message] = self.get_dispatched_messages('test-channel.outbound') message_id = (yield resp.json())['result']['message_id'] self.assertEqual(message['message_id'], message_id)
def test_send_message_reply(self): '''Sending a reply message should fetch the relevant inbound message, use it to construct a reply message, and place the reply message on the queue for the channel''' channel = Channel(redis_manager=(yield self.get_redis()), config=(yield self.create_channel_config()), properties=self.create_channel_properties(), id='test-channel') yield channel.save() yield channel.start(self.service) in_msg = TransportUserMessage(from_addr='+2789', to_addr='+1234', transport_name='test-channel', transport_type='_', transport_metadata={'foo': 'bar'}) yield self.api.inbounds.store_vumi_message('test-channel', in_msg) expected = in_msg.reply(content='testcontent') expected = api_from_message(expected) resp = yield self.post('/channels/test-channel/messages/', { 'reply_to': in_msg['message_id'], 'content': 'testcontent', }) yield self.assert_response(resp, http.OK, 'message sent', omit(expected, 'timestamp', 'message_id'), ignore=['timestamp', 'message_id']) [message] = self.get_dispatched_messages('test-channel.outbound') message_id = (yield resp.json())['result']['message_id'] self.assertEqual(message['message_id'], message_id)
def test_modify_channel_no_config_change(self): properties = self.create_channel_properties() config = yield self.create_channel_config() redis = yield self.get_redis() channel = Channel(redis, config, properties, id='test-channel') yield channel.save() yield channel.start(self.service) resp = yield self.post('/channels/test-channel', {'metadata': { 'foo': 'bar' }}) yield self.assert_response( resp, http.OK, 'channel updated', conjoin( properties, { 'status': self.generate_status(), 'id': 'test-channel', 'metadata': { 'foo': 'bar' }, }))
def test_plugin_channel_stopped(self): '''Stores the name of the function call and arguments in calls''' plugin = FakeJunebugPlugin() config = yield self.create_channel_config() yield plugin.start_plugin({'test': 'plugin_config'}, config) plugin.calls = [] redis = yield self.get_redis() channel = Channel(redis, config, deepcopy(self.default_channel_properties)) yield plugin.channel_stopped(channel) [(name, [channel_arg])] = plugin.calls self.assertEqual(name, 'channel_stopped') self.assertEqual(channel_arg, channel)
def send_message(self, request, body, channel_id): '''Send an outbound (mobile terminated) message''' if 'to' not in body and 'reply_to' not in body: raise ApiUsageError( 'Either "to" or "reply_to" must be specified') channel = yield Channel.from_id( self.redis, self.config, channel_id, self.service, self.plugins) if 'reply_to' in body: msg = yield channel.send_reply_message( self.message_sender, self.outbounds, self.inbounds, body, allow_expired_replies=self.config.allow_expired_replies) else: msg = yield channel.send_message( self.message_sender, self.outbounds, body) yield self.message_rate.increment( channel_id, 'outbound', self.config.metric_window) returnValue(response( request, 'message submitted', msg, code=http.CREATED))