class ContextTests(unittest.TestCase): def setUp(self): self.context = Context() def tearDown(self): del self.context collected = gc.collect() if collected: logging.info("Garbage collector: collected %d objects." % (collected)) def test_init(self): settings = { 'bot': { 'name': 'testy', 'version': '17.4.1' }, } self.context = Context(settings) self.assertEqual(self.context.get('bot.name'), 'testy') self.assertEqual(self.context.get('bot.version'), '17.4.1') def test_init_filter(self): self.context = Context(filter=lambda x, y: x + '...') self.context.apply({'my.var': 'my value'}) self.context.check('my.var', filter=True) self.assertEqual(self.context.get('my.var'), 'my value...') def test_apply(self): self.assertEqual(self.context.get('port'), None) settings = { 'spark': { 'CISCO_SPARK_BTTN_BOT': 'who_knows' }, 'spark.room': 'title', 'DEBUG': True, 'server': { 'port': 80, 'url': 'http://www.acme.com/' }, 'bot.store': { 'planets': ['Uranus', 'Mercury'] }, } self.context.apply(settings) self.assertEqual(self.context.get('DEBUG'), True) self.assertEqual(self.context.get('spark.CISCO_SPARK_BTTN_BOT'), 'who_knows') self.assertEqual(self.context.get('spark.room'), 'title') self.assertEqual(self.context.get('server.port'), 80) self.assertEqual(self.context.get('server.url'), 'http://www.acme.com/') self.assertEqual(self.context.get('bot.store.planets'), ['Uranus', 'Mercury']) self.assertEqual(self.context.get('bot.store'), {'planets': ['Uranus', 'Mercury']}) def test_clear(self): self.assertEqual(self.context.get('port'), None) settings = { 'spark': { 'CISCO_SPARK_BTTN_BOT': 'who_knows' }, 'spark.room': 'title', 'DEBUG': True, 'server': { 'port': 80, 'url': 'http://www.acme.com/' }, } self.context.apply(settings) self.assertEqual(self.context.get('DEBUG'), True) self.assertEqual(self.context.get('spark.CISCO_SPARK_BTTN_BOT'), 'who_knows') self.assertEqual(self.context.get('spark.room'), 'title') self.assertEqual(self.context.get('server.port'), 80) self.assertEqual(self.context.get('server.url'), 'http://www.acme.com/') self.context.clear() self.assertEqual(self.context.get('DEBUG'), None) self.assertEqual(self.context.get('spark.CISCO_SPARK_BTTN_BOT'), None) self.assertEqual(self.context.get('spark.room'), None) self.assertEqual(self.context.get('server.port'), None) self.assertEqual(self.context.get('server.url'), None) def test_is_empty(self): self.assertTrue(self.context.is_empty) # set a key self.context.set('hello', 'world') self.assertEqual(self.context.get('hello'), 'world') self.assertFalse(self.context.is_empty) self.context.clear() self.assertTrue(self.context.is_empty) settings = { 'spark': { 'CISCO_SPARK_BTTN_BOT': 'who_knows' }, 'spark.room': 'title', 'DEBUG': True, 'server': { 'port': 80, 'url': 'http://www.acme.com/' }, } self.context.apply(settings) self.assertFalse(self.context.is_empty) def test_check(self): self.assertEqual(self.context.get('spark.room'), None) settings = { 'spark': { 'room': 'My preferred channel', 'participants': ['*****@*****.**', '*****@*****.**'], 'team': 'Anchor team', 'token': 'hkNWEtMJNkODk3ZDZLOGQ0OVGlZWU1NmYtyY', 'weird_token': '$MY_FUZZY_SPARK_TOKEN', 'fuzzy_token': '$MY_FUZZY_SPARK_TOKEN', 'webhook': "http://73a1e282.ngrok.io", } } self.context.apply(settings) self.context.check('spark.room', is_mandatory=True) self.assertEqual(self.context.get('spark.room'), 'My preferred channel') self.context.check('spark.team') self.assertEqual(self.context.get('spark.team'), 'Anchor team') self.context.check('spark.*not*present') # will be set to None self.assertEqual(self.context.get('spark.*not*present'), None) self.context.check('spark.absent_list', default=[]) self.assertEqual(self.context.get('spark.absent_list'), []) self.context.check('spark.absent_dict', default={}) self.assertEqual(self.context.get('spark.absent_dict'), {}) self.context.check('spark.absent_text', default='*born') self.assertEqual(self.context.get('spark.absent_text'), '*born') # is_mandatory is useless if default is set self.context.check('spark.*not*present', default='*born', is_mandatory=True) self.assertEqual(self.context.get('spark.*not*present'), '*born') # missing key self.assertEqual(self.context.get('spark.*unknown*key*'), None) # we need the missing key with self.assertRaises(KeyError): self.context.check('spark.*unknown*key*', is_mandatory=True) # validate implies is_mandatory with self.assertRaises(KeyError): self.context.check('spark.*unknown*key*', validate=lambda line: True) # exception when is_mandatory is explicit with self.assertRaises(KeyError): self.context.check('spark.*unknown*key*', is_mandatory=True, filter=True) # yet filter does not imply is_mandatory by itself self.context.check('spark.*unknown*key*', filter=True) # warning in log # a web link has been set self.assertEqual(self.context.get('spark.webhook'), "http://73a1e282.ngrok.io") # validate http self.context.check('spark.webhook', validate=lambda line: line.startswith('http')) # validate https with self.assertRaises(ValueError): self.context.check('spark.webhook', validate=lambda line: line.startswith('https')) # a token has been set self.assertEqual(self.context.get('spark.token'), 'hkNWEtMJNkODk3ZDZLOGQ0OVGlZWU1NmYtyY') # validate length of token with self.assertRaises(ValueError): self.context.check('spark.token', validate=lambda line: len(line) == 32) # we rely on the environment for this key self.assertEqual(self.context.get('spark.weird_token'), '$MY_FUZZY_SPARK_TOKEN') # no change to the value self.context.check('spark.weird_token') # lookup the environment and change the value to None self.context.check('spark.weird_token', filter=True) # warning in log self.assertEqual(self.context.get('spark.weird_token'), None) # ensure the environment is clean def clear_env(name): try: os.environ.pop(name) except: pass clear_env('MY_FUZZY_SPARK_TOKEN') # a value based on the environment self.context.set('spark.fuzzy_token', '$MY_FUZZY_SPARK_TOKEN') self.context.check('spark.fuzzy_token') self.assertEqual(self.context.get('spark.fuzzy_token'), '$MY_FUZZY_SPARK_TOKEN') # default has no effect, mandatory is ok self.context.set('spark.fuzzy_token', '$MY_FUZZY_SPARK_TOKEN') self.context.check('spark.fuzzy_token', default='hello there') self.context.check('spark.fuzzy_token', is_mandatory=True) self.assertEqual(self.context.get('spark.fuzzy_token'), '$MY_FUZZY_SPARK_TOKEN') # default value is used if key is absent from the environment self.context.set('spark.fuzzy_token', '$MY_FUZZY_SPARK_TOKEN') self.context.check('spark.fuzzy_token', default='hello there', filter=True) self.assertEqual(self.context.get('spark.fuzzy_token'), 'hello there') # is_mandatory is useless in that case self.context.set('spark.fuzzy_token', '$MY_FUZZY_SPARK_TOKEN') self.context.check('spark.fuzzy_token', is_mandatory=True, filter=True) self.assertEqual(self.context.get('spark.fuzzy_token'), None) # set the value to '' self.context.set('spark.fuzzy_token', '$MY_FUZZY_SPARK_TOKEN') os.environ['MY_FUZZY_SPARK_TOKEN'] = '' self.context.check('spark.fuzzy_token', filter=True) self.assertEqual(self.context.get('spark.fuzzy_token'), '') # set the value to '' -- default value is useless in that case self.context.set('spark.fuzzy_token', '$MY_FUZZY_SPARK_TOKEN') os.environ['MY_FUZZY_SPARK_TOKEN'] = '' self.context.check('spark.fuzzy_token', default='ok?', filter=True) self.assertEqual(self.context.get('spark.fuzzy_token'), '') # set the value to 'hello' self.context.set('spark.fuzzy_token', '$MY_FUZZY_SPARK_TOKEN') os.environ['MY_FUZZY_SPARK_TOKEN'] = 'hello' self.context.check('spark.fuzzy_token', filter=True) self.assertEqual(self.context.get('spark.fuzzy_token'), 'hello') # set the value to 'hello' -- default value is useless in that case self.context.set('spark.fuzzy_token', '$MY_FUZZY_SPARK_TOKEN') os.environ['MY_FUZZY_SPARK_TOKEN'] = 'hello again' self.context.check('spark.fuzzy_token', default='ok?', filter=True) self.assertEqual(self.context.get('spark.fuzzy_token'), 'hello again') # pass the variable name as default value self.context.set('spark.fuzzy_token', None) os.environ['MY_FUZZY_SPARK_TOKEN'] = 'hello' self.context.check('spark.fuzzy_token', default='$MY_FUZZY_SPARK_TOKEN', filter=True) self.assertEqual(self.context.get('spark.fuzzy_token'), 'hello') # pass the variable name as default value -- no effect self.context.set('spark.fuzzy_token', '$MY_FUZZY_SPARK_TOKEN') os.environ['MY_FUZZY_SPARK_TOKEN'] = 'hello' self.context.check('spark.fuzzy_token', default='$MY_FUZZY_SPARK_TOKEN', filter=True) self.assertEqual(self.context.get('spark.fuzzy_token'), 'hello') # pass as default the name of an empty variable -- tricky case self.context.set('spark.fuzzy_token', '$MY_FUZZY_SPARK_TOKEN') clear_env('MY_FUZZY_SPARK_TOKEN') self.context.check('spark.fuzzy_token', default='$MY_FUZZY_SPARK_TOKEN', filter=True) self.assertEqual(self.context.get('spark.fuzzy_token'), None) def test__filter(self): self.assertEqual(Context._filter(None), None) self.assertEqual(Context._filter(''), '') self.assertEqual(Context._filter('ZLOGQ0OVGlZWU1NmYtyY'), 'ZLOGQ0OVGlZWU1NmYtyY') if os.environ.get('PATH') is not None: self.assertTrue(Context._filter('$PATH') != '$PATH') Context._filter('$TOTALLY*UNKNOWN*HERE') # warning in log def test_has(self): self.context.apply({ 'spark': { 'room': 'My preferred channel', 'participants': ['*****@*****.**', '*****@*****.**'], 'team': 'Anchor team', 'token': 'hkNWEtMJNkODk3ZDZLOGQ0OVGlZWU1NmYtyY', 'fuzzy_token': '$MY_FUZZY_SPARK_TOKEN', 'webhook': "http://73a1e282.ngrok.io", } }) # undefined prefix self.assertFalse(self.context.has('hello')) # top-level prefix self.assertTrue(self.context.has('spark')) # 2-level prefix self.assertTrue(self.context.has('spark.team')) # undefined 2-level prefix self.assertFalse(self.context.has('.token')) def test_getter(self): # undefined key self.assertEqual(self.context.get('hello'), None) # undefined key with default value whatever = 'whatever' self.assertEqual(self.context.get('hello', whatever), whatever) # set a key self.context.set('hello', 'world') self.assertEqual(self.context.get('hello'), 'world') # default value is meaningless when key has been set self.assertEqual(self.context.get('hello', 'whatever'), 'world') # except when set to None self.context.set('special', None) self.assertEqual(self.context.get('special', []), []) def test_unicode(self): self.context.set('hello', 'world') self.assertEqual(self.context.get('hello'), 'world') self.assertEqual(self.context.get(u'hello'), 'world') self.context.set('hello', u'wôrld') self.assertEqual(self.context.get('hello'), u'wôrld') self.context.set(u'hello', u'wôrld') self.assertEqual(self.context.get(u'hello'), u'wôrld') def test_increment(self): self.assertEqual(self.context.get('gauge'), None) value = self.context.increment('gauge') self.assertEqual(value, 1) self.context.set('gauge', 'world') self.assertEqual(self.context.get('gauge'), 'world') value = self.context.increment('gauge') self.assertEqual(value, 1) def test_decrement(self): self.assertEqual(self.context.get('gauge'), None) value = self.context.decrement('gauge') self.assertEqual(value, -1) self.context.set('gauge', 'world') self.assertEqual(self.context.get('gauge'), 'world') value = self.context.decrement('gauge') self.assertEqual(value, -1) def test_gauge(self): # undefined key self.assertEqual(self.context.get('gauge'), None) # see if type mismatch would create an error self.context.set('gauge', 'world') self.assertEqual(self.context.get('gauge'), 'world') # increment and decrement the counter value = self.context.increment('gauge') self.assertEqual(value, 1) self.assertEqual(self.context.get('gauge'), 1) self.assertEqual(self.context.decrement('gauge', 2), -1) self.assertEqual(self.context.increment('gauge', 4), 3) self.assertEqual(self.context.decrement('gauge', 10), -7) self.assertEqual(self.context.increment('gauge', 27), 20) self.assertEqual(self.context.get('gauge'), 20) # default value is meaningless when key has been set self.assertEqual(self.context.get('gauge', 'world'), 20) # reset the gauge self.context.set('gauge', 123) self.assertEqual(self.context.get('gauge'), 123) def test_concurrency(self): def worker(id, context): for i in range(4): r = random.random() time.sleep(r) value = context.increment('gauge') logging.info('worker %d:counter=%d' % (id, value)) logging.info('worker %d:done' % id) logging.info('Creating a counter') self.counter = Context() logging.info('Launching incrementing workers') workers = [] for i in range(4): p = Process(target=worker, args=( i, self.counter, )) p.start() workers.append(p) logging.info('Waiting for worker threads') for p in workers: p.join() logging.info('Counter: %d' % self.counter.get('gauge')) self.assertEqual(self.counter.get('gauge'), 16)
class EngineTests(unittest.TestCase): def setUp(self): self.context = Context() self.engine = Engine(context=self.context, mouth=Queue()) self.space = LocalSpace(context=self.context) self.engine.space = self.space def tearDown(self): del self.space del self.engine del self.context collected = gc.collect() if collected: logging.info("Garbage collector: collected %d objects." % (collected)) def test_init(self): logging.info('*** init ***') engine = Engine(context=self.context) self.assertEqual(engine.context, self.context) self.assertTrue(engine.mouth is None) self.assertTrue(engine.speaker is not None) self.assertTrue(engine.ears is None) self.assertTrue(engine.listener is not None) self.assertTrue(engine.fan is None) self.assertTrue(engine.observer is not None) self.assertTrue(engine.registered is not None) self.assertEqual(engine.bots, {}) self.assertFalse(engine.space is None) self.assertTrue(engine.server is None) self.assertTrue(engine.shell is not None) self.assertEqual(engine.driver, ShellBot) self.assertEqual(engine.machine_factory, None) self.assertEqual(engine.updater_factory, None) del engine engine = Engine(context=self.context, type='local', mouth='m', ears='e', fan='f') self.assertEqual(engine.context, self.context) self.assertEqual(engine.mouth, 'm') self.assertTrue(engine.speaker is not None) self.assertEqual(engine.ears, 'e') self.assertTrue(engine.listener is not None) self.assertEqual(engine.fan, 'f') self.assertTrue(engine.observer is not None) self.assertTrue(engine.registered is not None) self.assertEqual(engine.bots, {}) self.assertTrue(engine.space is not None) self.assertTrue(engine.server is None) self.assertTrue(engine.shell is not None) self.assertEqual(engine.driver, ShellBot) self.assertEqual(engine.machine_factory, None) self.assertEqual(engine.updater_factory, None) del engine engine = Engine(context=self.context, space=self.space, mouth='m', ears='e', fan='f') self.assertEqual(engine.context, self.context) self.assertEqual(engine.mouth, 'm') self.assertTrue(engine.speaker is not None) self.assertEqual(engine.ears, 'e') self.assertTrue(engine.listener is not None) self.assertEqual(engine.fan, 'f') self.assertTrue(engine.observer is not None) self.assertTrue(engine.registered is not None) self.assertEqual(engine.bots, {}) self.assertEqual(engine.space, self.space) self.assertTrue(engine.server is None) self.assertTrue(engine.shell is not None) self.assertEqual(engine.driver, ShellBot) self.assertEqual(engine.machine_factory, None) self.assertEqual(engine.updater_factory, None) del engine engine = Engine( context=self.context, driver=FakeBot, machine_factory=MachineFactory, updater_factory=MyUpdaterFactory, ) self.assertEqual(engine.context, self.context) self.assertEqual(engine.mouth, None) self.assertTrue(engine.speaker is not None) self.assertEqual(engine.ears, None) self.assertTrue(engine.listener is not None) self.assertTrue(engine.fan is None) self.assertTrue(engine.observer is not None) self.assertTrue(engine.registered is not None) self.assertEqual(engine.bots, {}) self.assertTrue(engine.space is not None) self.assertTrue(engine.server is None) self.assertTrue(engine.shell is not None) self.assertEqual(engine.driver, FakeBot) self.assertEqual(engine.machine_factory, MachineFactory) self.assertEqual(engine.updater_factory, MyUpdaterFactory) self.context.apply({ 'bot': { 'name': 'testy', 'version': '17.4.1' }, }) engine = Engine(context=self.context) self.assertEqual(engine.name, 'testy') self.assertEqual(engine.version, '17.4.1') del engine def test_configure(self): logging.info('*** configure ***') self.engine.configure({}) self.assertEqual(self.engine.space.ears, self.engine.ears) self.assertTrue(self.engine.list_factory is not None) self.engine.context.clear() settings = { 'bot': { 'on_enter': 'Hello!', 'on_exit': 'Bye!', }, 'localized': { 'hello world': "What'up, Doc?", 'another string': 'Bye!', }, 'space': { 'title': 'space name', 'participants': ['*****@*****.**'], }, 'server': { 'url': 'http://to.no.where', 'hook': '/hook', 'binding': '0.0.0.0', 'port': 8080, }, } self.engine.configure(settings) self.assertEqual(self.engine.get('bot.on_enter'), 'Hello!') self.assertEqual(self.engine.get('bot.on_exit'), 'Bye!') self.assertEqual(self.engine.get('space.title'), 'space name') self.assertEqual(self.engine.get('space.participants'), ['*****@*****.**']) self.assertEqual(self.engine.get('server.url'), 'http://to.no.where') self.assertEqual(self.engine.get('server.hook'), '/hook') self.assertEqual(_('hello world'), "What'up, Doc?") self.assertEqual(_('not localized'), 'not localized') self.engine.context.clear() self.engine.configure_from_path( os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test_settings', 'regular.yaml')) self.assertEqual(self.engine.get('bot.on_enter'), 'How can I help you?') self.assertEqual(self.engine.get('bot.on_exit'), 'Bye for now') self.assertEqual(self.engine.get('space.title'), 'Support channel') self.assertEqual(self.engine.get('space.participants'), ['*****@*****.**', '*****@*****.**']) self.assertEqual(self.engine.get('server.url'), None) self.assertEqual(self.engine.get('server.hook'), None) self.assertEqual(self.engine.get('server.binding'), None) self.assertEqual(self.engine.get('server.port'), None) items = [x for x in self.engine.list_factory.get_list('SupportTeam')] self.assertEqual(items, ['*****@*****.**', '*****@*****.**']) items = [x for x in self.engine.list_factory.get_list('*unknown*list')] self.assertEqual(items, []) names = self.engine.list_factory.list_commands() self.assertEqual(sorted(names), ['SupportTeam']) def test_configuration_2(self): logging.info('*** configure 2 ***') settings = { 'bot': { 'on_enter': 'Hello!', 'on_exit': 'Bye!', }, 'space': { 'title': 'Support channel', }, 'server': { 'url': 'http://to.nowhere/', 'trigger': '/trigger', 'hook': '/hook', 'binding': '0.0.0.0', 'port': 8080, }, } clear_env('CHANNEL_DEFAULT_PARTICIPANTS') context = Context(settings) engine = Engine(context=context, configure=True) self.assertEqual(engine.get('bot.on_enter'), 'Hello!') self.assertEqual(engine.get('bot.on_exit'), 'Bye!') self.assertEqual(engine.get('space.title'), 'Support channel') self.assertEqual(engine.get('space.participants'), None) self.assertEqual(engine.get('server.url'), 'http://to.nowhere/') self.assertEqual(engine.get('server.hook'), '/hook') self.assertEqual(engine.get('server.trigger'), '/trigger') self.assertEqual(engine.get('server.binding'), None) self.assertEqual(engine.get('server.port'), 8080) def test_configure_default(self): logging.info('*** configure with default values ***') clear_env("BOT_BANNER_TEXT") clear_env("BOT_BANNER_CONTENT") clear_env("BOT_BANNER_FILE") clear_env("BOT_ON_ENTER") clear_env("BOT_ON_EXIT") clear_env("CHAT_ROOM_TITLE") clear_env("CHANNEL_DEFAULT_PARTICIPANTS") clear_env("CISCO_SPARK_BOT_TOKEN") clear_env("SERVER_URL") self.engine.configure() # logging.debug(self.engine.context.values) self.assertEqual(self.engine.get('bot.banner.text'), None) self.assertEqual(self.engine.get('bot.banner.content'), None) self.assertEqual(self.engine.get('bot.banner.file'), None) self.assertEqual(self.engine.get('bot.on_enter'), None) self.assertEqual(self.engine.get('bot.on_exit'), None) self.assertEqual(self.engine.get('space.title'), 'Collaboration space') self.assertEqual(self.engine.get('space.participants'), None) self.assertEqual(self.engine.get('space.unknown'), None) self.assertEqual(self.engine.get('server.url'), '$SERVER_URL') self.assertEqual(self.engine.get('server.hook'), '/hook') self.assertEqual(self.engine.get('server.binding'), None) self.assertEqual(self.engine.get('server.port'), 8080) self.assertEqual(self.engine.space.ears, self.engine.ears) self.assertTrue(self.engine.bus is not None) self.assertTrue(self.engine.publisher is not None) def test_configure_environment(self): logging.info('*** configure from the environment ***') os.environ["BOT_BANNER_TEXT"] = 'some text' os.environ["BOT_BANNER_CONTENT"] = 'some content' os.environ["BOT_BANNER_FILE"] = 'some link' os.environ["BOT_ON_ENTER"] = 'Hello!' os.environ["BOT_ON_EXIT"] = 'Bye!' os.environ["CHAT_ROOM_TITLE"] = 'Support channel' os.environ["CHANNEL_DEFAULT_PARTICIPANTS"] = '*****@*****.**' os.environ["CISCO_SPARK_BOT_TOKEN"] = '*token' os.environ["SERVER_URL"] = 'http://to.nowhere/' self.engine.configure() # logging.debug(self.engine.context.values) self.assertEqual(self.engine.get('bot.banner.text'), 'some text') self.assertEqual(self.engine.get('bot.banner.content'), 'some content') self.assertEqual(self.engine.get('bot.banner.file'), 'some link') self.assertEqual(self.engine.get('bot.on_enter'), 'Hello!') self.assertEqual(self.engine.get('bot.on_exit'), 'Bye!') self.assertEqual(self.engine.get('space.title'), 'Support channel') self.assertEqual(self.engine.get('space.participants'), '*****@*****.**') self.assertEqual(self.engine.get('space.unknown'), None) self.assertEqual(self.engine.get('server.url'), '$SERVER_URL') self.assertEqual(self.engine.get('server.hook'), '/hook') self.assertEqual(self.engine.get('server.binding'), None) self.assertEqual(self.engine.get('server.port'), 8080) def test_get(self): logging.info('*** get ***') os.environ["BOT_ON_ENTER"] = 'Hello!' os.environ["BOT_ON_EXIT"] = 'Bye!' os.environ["CHAT_ROOM_TITLE"] = 'Support channel' os.environ["CHANNEL_DEFAULT_PARTICIPANTS"] = '*****@*****.**' os.environ["CISCO_SPARK_BOT_TOKEN"] = '*token' os.environ["SERVER_URL"] = 'http://to.nowhere/' settings = { 'bot': { 'on_enter': 'Hello!', 'on_exit': 'Bye!', }, 'space': { 'title': '$CHAT_ROOM_TITLE', }, 'server': { 'url': '$SERVER_URL', 'hook': '/hook', 'binding': '0.0.0.0', 'port': 8080, }, } self.engine.configure(settings=settings) self.assertEqual(self.engine.get('bot.on_enter'), 'Hello!') self.assertEqual(self.engine.get('bot.on_exit'), 'Bye!') self.assertEqual(self.engine.get('space.title'), 'Support channel') self.assertEqual(self.engine.get('space.participants'), '*****@*****.**') self.assertEqual(self.engine.get('space.unknown'), None) self.assertEqual(self.engine.get('server.url'), 'http://to.nowhere/') self.assertEqual(self.engine.get('server.hook'), '/hook') self.assertEqual(self.engine.get('server.binding'), None) self.assertEqual(self.engine.get('server.port'), 8080) def test_set(self): logging.info('*** set ***') self.engine.set('hello', 'world') self.assertEqual(self.engine.get('hello'), 'world') self.assertEqual(self.engine.get(u'hello'), 'world') self.engine.set('hello', u'wôrld') self.assertEqual(self.engine.get('hello'), u'wôrld') self.engine.set(u'hello', u'wôrld') self.assertEqual(self.engine.get(u'hello'), u'wôrld') def test_name(self): logging.info('*** name ***') self.assertEqual(self.engine.name, 'Shelly') def test_version(self): logging.info('*** version ***') self.assertEqual(self.engine.version, '*unknown*') def test_register(self): logging.info('*** register ***') with self.assertRaises(AttributeError): self.engine.register('*unknown*event', lambda: 'ok') with self.assertRaises(AttributeError): self.engine.register('bond', lambda: 'ok') with self.assertRaises(AttributeError): self.engine.register('dispose', lambda: 'ok') counter = MyCounter('counter #1') with self.assertRaises(AssertionError): self.engine.register(None, counter) with self.assertRaises(AssertionError): self.engine.register('', counter) with self.assertRaises(AssertionError): self.engine.register(1.2, counter) self.engine.register('bond', counter) self.engine.register('dispose', counter) with self.assertRaises(AttributeError): self.engine.register('start', counter) with self.assertRaises(AttributeError): self.engine.register('stop', counter) with self.assertRaises(AttributeError): self.engine.register('*unknown*event', counter) self.engine.register('bond', MyCounter('counter #2')) class AllEvents(object): def on_bond(self, bot): pass def on_dispose(self): pass def on_start(self): pass def on_stop(self): pass def on_message(self): pass def on_join(self): pass def on_leave(self): pass def on_enter(self): pass def on_exit(self): pass def on_inbound(self): pass def on_some_custom_event(self): pass all_events = AllEvents() self.engine.register('bond', all_events) self.engine.register('dispose', all_events) self.engine.register('start', all_events) self.engine.register('stop', all_events) self.engine.register('message', all_events) self.engine.register('join', all_events) self.engine.register('leave', all_events) self.engine.register('enter', all_events) self.engine.register('exit', all_events) self.engine.register('inbound', all_events) self.engine.register('some_custom_event', all_events) self.assertEqual(len(self.engine.registered['bond']), 3) self.assertEqual(len(self.engine.registered['dispose']), 2) self.assertEqual(len(self.engine.registered['start']), 1) self.assertEqual(len(self.engine.registered['stop']), 1) self.assertEqual(len(self.engine.registered['message']), 1) self.assertEqual(len(self.engine.registered['join']), 1) self.assertEqual(len(self.engine.registered['leave']), 1) self.assertEqual(len(self.engine.registered['enter']), 1) self.assertEqual(len(self.engine.registered['exit']), 1) self.assertEqual(len(self.engine.registered['inbound']), 1) self.assertEqual(len(self.engine.registered['some_custom_event']), 1) def test_dispatch(self): logging.info('*** dispatch ***') counter = MyCounter('counter #1') self.engine.register('bond', counter) self.engine.register('dispose', counter) self.engine.register('bond', MyCounter('counter #2')) self.engine.register('dispose', MyCounter('counter #3')) class AllEvents(object): def __init__(self): self.events = [] def on_bond(self, bot): self.events.append('bond') def on_dispose(self): self.events.append('dispose') def on_start(self): self.events.append('start') def on_stop(self): self.events.append('stop') def on_message(self, received): assert received == '*void' self.events.append('message') def on_join(self, received): assert received == '*void' self.events.append('join') def on_leave(self, received): assert received == '*void' self.events.append('leave') def on_enter(self, received): assert received == '*void' self.events.append('enter') def on_exit(self, received): assert received == '*void' self.events.append('exit') def on_inbound(self, received): assert received == '*void' self.events.append('inbound') def on_some_custom_event(self, data): assert data == '*data' self.events.append('some_custom_event') all_events = AllEvents() self.engine.register('bond', all_events) self.engine.register('dispose', all_events) self.engine.register('start', all_events) self.engine.register('stop', all_events) self.engine.register('message', all_events) self.engine.register('join', all_events) self.engine.register('leave', all_events) self.engine.register('enter', all_events) self.engine.register('exit', all_events) self.engine.register('inbound', all_events) self.engine.register('some_custom_event', all_events) self.engine.dispatch('bond', bot='*dummy') self.engine.dispatch('dispose') self.engine.dispatch('start') self.engine.dispatch('stop') self.engine.dispatch('message', received='*void') self.engine.dispatch('join', received='*void') self.engine.dispatch('leave', received='*void') self.engine.dispatch('enter', received='*void') self.engine.dispatch('exit', received='*void') self.engine.dispatch('inbound', received='*void') self.engine.dispatch('some_custom_event', data='*data') with self.assertRaises(AssertionError): self.engine.dispatch('*unknown*event') self.assertEqual(counter.count, 2) self.assertEqual(all_events.events, [ 'bond', 'dispose', 'start', 'stop', 'message', 'join', 'leave', 'enter', 'exit', 'inbound', 'some_custom_event' ]) def test_load_commands(self): logging.info('*** load_commands ***') with mock.patch.object(self.engine.shell, 'load_commands', return_value=None) as mocked: self.engine.load_commands(['a', 'b', 'c', 'd']) mocked.assert_called_with(['a', 'b', 'c', 'd']) def test_load_command(self): logging.info('*** load_command ***') with mock.patch.object(self.engine.shell, 'load_command', return_value=None) as mocked: self.engine.load_command('a') mocked.assert_called_with('a') def test_hook(self): logging.info('*** hook ***') self.context.set('server.url', 'http://here.you.go:123') server = mock.Mock() with mock.patch.object(self.engine.space, 'register', return_value=None) as mocked: self.engine.hook(server=server) self.assertFalse(mocked.called) self.context.set('server.binding', '0.0.0.0') self.engine.hook(server=server) mocked.assert_called_with(hook_url='http://here.you.go:123/hook') def test_get_hook(self): logging.info('*** get_hook ***') self.context.set('server.url', 'http://here.you.go:123') self.assertEqual(self.engine.get_hook(), self.engine.space.webhook) def test_run(self): logging.info('*** run ***') engine = Engine(context=self.context) engine.space = LocalSpace(context=self.context) engine.start = mock.Mock() engine.space.run = mock.Mock() engine.run() self.assertTrue(engine.start.called) self.assertTrue(engine.space.run.called) class MyServer(object): def __init__(self, engine): self.engine = engine def add_route(self, route, **kwargs): pass def run(self): self.engine.set("has_been_ran", True) server = MyServer(engine=engine) engine.run(server=server) self.assertTrue(engine.get("has_been_ran")) def test_start(self): logging.info('*** start ***') engine = Engine(context=self.context) engine.space = LocalSpace(context=self.context) engine.start_processes = mock.Mock() engine.on_start = mock.Mock() engine.start() self.assertTrue(engine.ears is not None) self.assertTrue(engine.mouth is not None) self.assertTrue(engine.start_processes.called) self.assertTrue(engine.on_start.called) def test_static(self): logging.info('*** static test ***') self.engine.configure() self.context.set('bus.address', 'tcp://127.0.0.1:6666') self.engine.listener.DEFER_DURATION = 0.0 self.engine.publisher.DEFER_DURATION = 0.0 self.engine.start() self.engine.stop() self.assertEqual(self.engine.get('listener.counter', 0), 0) self.assertEqual(self.engine.get('speaker.counter', 0), 0) def test_bond(self): logging.info("*** bond") self.space.delete = mock.Mock() channel = self.engine.bond(title=None) self.assertEqual(channel.id, '*local') self.assertEqual(channel.title, 'Collaboration space') channel = self.engine.bond(title='') self.assertEqual(channel.id, '*local') self.assertEqual(channel.title, 'Collaboration space') channel = self.engine.bond(title='hello world') self.assertEqual(channel.id, '*local') self.assertEqual(channel.title, 'hello world') self.assertFalse(self.space.delete.called) channel = self.engine.bond(reset=True) self.assertTrue(self.space.delete.called) self.space.add_participants = mock.Mock() self.engine.dispatch = mock.Mock() with mock.patch.object(self.space, 'get_by_title', return_value=None) as mocked: self.engine.bond( title='my title', participants=['c', 'd'], ) mocked.assert_called_with(title='my title') self.space.add_participants.assert_called_with(id='*local', persons=['c', 'd']) self.space.configure( settings={ 'space': { 'title': 'Another title', 'participants': ['*****@*****.**', '*****@*****.**'], } }) with mock.patch.object(self.space, 'get_by_title', return_value=None) as mocked: self.engine.bond() mocked.assert_called_with(title='Another title') self.space.add_participants.assert_called_with( id='*local', persons=['*****@*****.**', '*****@*****.**']) def test_enumerate_bots(self): logging.info('*** enumerate_bots ***') self.engine.bots = { '123': FakeBot(self.engine, '123'), '456': FakeBot(self.engine, '456'), '789': FakeBot(self.engine, '789'), } for bot in self.engine.enumerate_bots(): self.assertTrue(bot.id in ['123', '456', '789']) def test_get_bot(self): logging.info('*** get_bot ***') self.engine.bots = { '123': FakeBot(self.engine, '123'), '456': FakeBot(self.engine, '456'), '789': FakeBot(self.engine, '789'), } bot = self.engine.get_bot('123') self.assertEqual(bot.id, '123') self.assertEqual(bot, self.engine.bots['123']) bot = self.engine.get_bot('456') self.assertEqual(bot.id, '456') self.assertEqual(bot, self.engine.bots['456']) bot = self.engine.get_bot('789') self.assertEqual(bot.id, '789') self.assertEqual(bot, self.engine.bots['789']) with mock.patch.object(self.engine, 'build_bot', return_value=FakeBot(self.engine, '*bot')) as mocked: bot = self.engine.get_bot() self.assertEqual(bot.id, '*bot') self.assertTrue('*bot' in self.engine.bots.keys()) def test_build_bot(self): logging.info('*** build_bot ***') self.engine.context.apply(self.engine.DEFAULT_SETTINGS) self.engine.bots = {} bot = self.engine.build_bot('123', FakeBot) self.assertEqual(bot.id, '123') bot.store.remember('a', 'b') self.assertEqual(bot.store.recall('a'), 'b') bot = self.engine.build_bot('456', FakeBot) self.assertEqual(bot.id, '456') bot.store.remember('c', 'd') self.assertEqual(bot.store.recall('a'), None) self.assertEqual(bot.store.recall('c'), 'd') bot = self.engine.build_bot('789', FakeBot) self.assertEqual(bot.id, '789') bot.store.remember('e', 'f') self.assertEqual(bot.store.recall('a'), None) self.assertEqual(bot.store.recall('c'), None) self.assertEqual(bot.store.recall('e'), 'f') def test_on_build(self): logging.info('*** on_build ***') bot = ShellBot(engine=self.engine) self.engine.on_build(bot) def test_build_store(self): logging.info('*** build_store ***') store_1 = self.engine.build_store('123') store_1.append('names', 'Alice') store_1.append('names', 'Bob') self.assertEqual(store_1.recall('names'), ['Alice', 'Bob']) store_2 = self.engine.build_store('456') store_2.append('names', 'Chloe') store_2.append('names', 'David') self.assertEqual(store_2.recall('names'), ['Chloe', 'David']) self.assertEqual(store_1.recall('names'), ['Alice', 'Bob']) store_2.forget() self.assertEqual(store_1.recall('names'), ['Alice', 'Bob']) self.assertEqual(store_2.recall('names'), None) def test_initialize_store(self): logging.info('*** initialize_store ***') settings = {'bot.store': {'planets': ['Uranus', 'Mercury']}} self.engine.context.apply(settings) print(self.engine.get('bot.store')) bot = self.engine.build_bot('123', FakeBot) self.assertEqual(bot.store.recall('planets'), ['Uranus', 'Mercury']) def test_build_machine(self): logging.info('*** build_machine ***') bot = ShellBot(engine=self.engine) machine = self.engine.build_machine(bot) previous = self.engine.machine_factory self.engine.machine_factory = MachineFactory( module='shellbot.machines.base', name='Machine') machine = self.engine.build_machine(bot) self.engine.machine_factory = previous def test_build_updater(self): logging.info('*** build_updater ***') updater = self.engine.build_updater('*id') self.assertEqual(updater, None) self.engine.updater_factory = MyUpdaterFactory() updater = self.engine.build_updater('*id') self.assertEqual(updater.id, '*id')
class SpaceTests(unittest.TestCase): def setUp(self): self.context = Context() self.space = Space(context=self.context) def tearDown(self): del self.space del self.context collected = gc.collect() if collected: logging.info("Garbage collector: collected %d objects." % (collected)) def test_init(self): logging.info("*** init") logging.debug("- default init") self.assertEqual(self.space.ears, None) self.assertEqual(self.space.fan, None) logging.debug("- unknown parameter") space = Space(context=self.context, weird='w') with self.assertRaises(AttributeError): self.assertEqual(space.weird, 'w') logging.debug("- extended parameters") class ExSpace(Space): def on_init(self, ex_token=None, **kwargs): self.token = ex_token space = ExSpace(context=self.context, ears='e', fan='f', ex_token='*token', ex_unknown='*weird') self.assertEqual(space.ears, 'e') self.assertEqual(space.fan, 'f') self.assertEqual(space.token, '*token') with self.assertRaises(AttributeError): self.assertTrue(space.unknown is not None) with self.assertRaises(AttributeError): self.assertTrue(space.ex_unknown is not None) logging.debug("- initialised via configuration") space = LocalSpace(context=self.context) space.configure({ 'space': { 'title': 'Another title', 'participants': ['*****@*****.**', '*****@*****.**'], } }) self.assertEqual(space.configured_title(), 'Another title') def test_on_start(self): logging.info("*** on_start") self.space.on_start() def test_on_stop(self): logging.info("*** on_stop") self.space.on_stop() def test_configure(self): logging.info("*** configure") class ExSpace(Space): def check(self): self.context.check('space.title', is_mandatory=True) settings = {'space.key': 'my value'} space = ExSpace(context=self.context) with self.assertRaises(KeyError): space.configure(settings=settings) self.assertEqual(space.context.get('space.title'), None) self.assertEqual(space.context.get('space.key'), 'my value') def test_configured_title(self): logging.info("*** configured_title") space = Space(context=self.context) self.assertEqual(space.configured_title(), space.DEFAULT_SPACE_TITLE) settings = {'space.title': 'my channel'} space.configure(settings=settings) self.assertEqual(self.context.get('space.title'), 'my channel') self.assertEqual(space.context.get('space.title'), 'my channel') self.assertEqual(space.configured_title(), 'my channel') def test_connect(self): logging.info("*** connect") self.space.connect() def test_list_group_channels(self): logging.info("*** list_group_channels") with self.assertRaises(NotImplementedError): channels = self.space.list_group_channels() def test_create(self): logging.info("*** create") with self.assertRaises(NotImplementedError): channel = self.space.create(title='*title') def test_get_by_title(self): logging.info("*** get_by_title") with self.assertRaises(AssertionError): self.space.get_by_title(None) with self.assertRaises(AssertionError): self.space.get_by_title('') self.assertEqual(self.space.get_by_title(title='*unknown'), None) def test_get_by_id(self): logging.info("*** get_by_id") with self.assertRaises(AssertionError): self.space.get_by_id(None) with self.assertRaises(AssertionError): self.space.get_by_id('') self.assertEqual(self.space.get_by_id(id='*unknown'), None) def test_get_by_person(self): logging.info("*** get_by_person") with self.assertRaises(AssertionError): self.space.get_by_person(None) with self.assertRaises(AssertionError): self.space.get_by_person('') self.assertEqual(self.space.get_by_person('*unknown'), None) def test_update(self): logging.info("*** update") with self.assertRaises(NotImplementedError): self.space.update(channel=FakeChannel()) def test_delete(self): logging.info("*** delete") with self.assertRaises(NotImplementedError): self.space.delete(id='*id') def test_list_participants(self): logging.info("*** list_participants") with self.assertRaises(NotImplementedError): self.space.list_participants(id='*id') def test_add_participants(self): logging.info("*** add_participants") with mock.patch.object(self.space, 'add_participant') as mocked: self.space.add_participants(id='*id', persons=[]) self.assertFalse(mocked.called) class MySpace(Space): def on_init(self): self._persons = [] def add_participant(self, id, person): self._persons.append(person) space = MySpace(context=self.context) space.add_participants(id='*id', persons=['*****@*****.**', '*****@*****.**']) self.assertEqual(space._persons, ['*****@*****.**', '*****@*****.**']) def test_add_participant(self): logging.info("*** add_participant") with self.assertRaises(NotImplementedError): self.space.add_participant(id='*id', person='*****@*****.**') def test_remove_participants(self): logging.info("*** remove_participants") with mock.patch.object(self.space, 'remove_participant') as mocked: self.space.remove_participants(id='*id', persons=[]) self.assertFalse(mocked.called) class MySpace(Space): def on_init(self): self._persons = ['*****@*****.**', '*****@*****.**'] def remove_participant(self, id, person): self._persons.remove(person) space = MySpace(context=self.context) space.remove_participants(id='*id', persons=['*****@*****.**', '*****@*****.**']) self.assertEqual(space._persons, []) def test_remove_participant(self): logging.info("*** remove_participant") with self.assertRaises(NotImplementedError): self.space.remove_participant(id='*id', person='*****@*****.**') def test_walk_messages(self): logging.info("*** walk_messages") with self.assertRaises(NotImplementedError): message = next(self.space.walk_messages(id='*id')) def test_post_message(self): logging.info("*** post_message") with self.assertRaises(AssertionError): # missing id and person self.space.post_message(text="What's up, Doc?") with self.assertRaises(AssertionError): # too much: id and person self.space.post_message(id='1', person='2', text="What's up, Doc?") with self.assertRaises(NotImplementedError): self.space.post_message(id='*id', text="What's up, Doc?") with self.assertRaises(NotImplementedError): self.space.post_message(person='*****@*****.**', text="What's up, Doc?") def test_webhook(self): logging.info("*** webhook") with self.assertRaises(NotImplementedError): self.space.webhook() def test_register(self): logging.info("*** register") with self.assertRaises(NotImplementedError): self.space.register(hook_url='http://no.where/') def test_deregister(self): logging.info("*** deregister") self.space.deregister() def test_start(self): logging.info("*** start") space = Space(context=self.context) space.register = mock.Mock() space.pull = mock.Mock() space.start(hook_url='http:/who.knows/') space.register.assert_called_with(hook_url='http:/who.knows/') self.assertFalse(space.pull.called) class ExSpace(Space): def on_reset(self): self._bot_id = None def on_start(self): self._bot_id = 123 space = ExSpace(context=self.context) space.register = mock.Mock() space.pull = mock.Mock() space.PULL_INTERVAL = 0.01 space.start() time.sleep(0.1) while space._bot_id is None: time.sleep(0.1) while self.context.get('puller.counter', 0) < 4: time.sleep(0.1) self.context.set('general.switch', 'off') self.assertFalse(space.register.called) self.assertEqual(space._bot_id, 123) self.assertTrue(self.context.get('puller.counter') > 3) def test_run(self): logging.info("*** run") space = Space(context=self.context) space.pull = mock.Mock(side_effect=Exception('TEST')) space.run() self.assertEqual(self.context.get('puller.counter'), 0) space = Space(context=self.context) space.pull = mock.Mock(side_effect=KeyboardInterrupt('ctl-C')) space.run() self.assertEqual(self.context.get('puller.counter'), 0) def test_pull(self): logging.info("*** pull") with self.assertRaises(NotImplementedError): self.space.pull()
class BotTests(unittest.TestCase): def setUp(self): self.context = Context() self.engine = Engine(context=self.context, ears=Queue(), mouth=Queue()) self.engine.bus = Bus(self.context) self.engine.bus.check() self.engine.publisher = self.engine.bus.publish() self.space = LocalSpace(context=self.context, ears=self.engine.ears) self.store = MemoryStore(context=self.context) self.bot = ShellBot(engine=self.engine, space=self.space, store=self.store) self.channel = Channel({'id': '*id', 'title': '*title'}) def tearDown(self): del self.channel del self.bot del self.store del self.space del self.engine.publisher del self.engine.bus del self.engine del self.context collected = gc.collect() if collected: logging.info("Garbage collector: collected %d objects." % (collected)) def test_init(self): logging.info('*** init ***') bot = ShellBot(engine=self.engine) self.assertEqual(bot.engine, self.engine) self.assertTrue(bot.space is not None) self.assertTrue(bot.channel is None) self.assertFalse(bot.store is None) self.assertFalse(bot.fan is None) self.assertTrue(bot.machine is None) bot = ShellBot(engine=self.engine, space=self.space, store=self.store, fan='f') self.assertEqual(bot.engine, self.engine) self.assertEqual(bot.space, self.space) self.assertEqual(bot.store, self.store) self.assertEqual(bot.fan, 'f') def test_on_init(self): logging.info('*** on_init ***') bot = ShellBot(engine=self.engine, fan='f') bot.on_init() def test_is_ready(self): logging.info("*** is_ready") self.bot.channel = None self.assertFalse(self.bot.is_ready) self.bot.channel = self.channel self.assertTrue(self.bot.is_ready) def test_id(self): logging.info("*** id") self.bot.channel = None self.assertEqual(self.bot.id, None) self.bot.channel = self.channel self.assertEqual(self.bot.id, '*id') def test_title(self): logging.info("*** title") self.bot.channel = None self.assertEqual(self.bot.title, None) self.bot.channel = self.channel self.assertEqual(self.bot.title, '*title') def test_reset(self): logging.info("*** reset") self.bot.channel = self.channel self.bot.reset() self.assertEqual(self.bot.channel, None) def test_on_reset(self): logging.info("*** on_reset") self.bot.on_reset() def test_bond(self): logging.info("*** bond") self.bot.channel = self.channel self.bot.bond() def test_on_bond(self): logging.info("*** on_bond") self.bot.on_bond() def test_on_enter(self): logging.info("*** on_enter") self.bot.on_enter() def test_dispose(self): logging.info("*** dispose") self.engine.dispatch = mock.Mock() self.space.delete = mock.Mock() self.bot.dispose() self.assertFalse(self.engine.dispatch.called) self.assertFalse(self.space.delete.called) self.bot.channel = self.channel self.bot.dispose() self.assertTrue(self.engine.dispatch.called) self.assertTrue(self.space.delete.called) self.assertEqual(self.bot.channel, None) def test_on_exit(self): logging.info("*** on_exit") self.bot.on_exit() def test_add_participants(self): logging.info('*** add_participants ***') self.bot.channel = self.channel with mock.patch.object(self.bot.space, 'add_participants', return_value=None) as mocked: self.bot.add_participants(['a', 'b', 'c', 'd']) mocked.assert_called_with(id='*id', persons=['a', 'b', 'c', 'd']) def test_add_participant(self): logging.info('*** add_participant ***') self.bot.channel = self.channel with mock.patch.object(self.bot.space, 'add_participant', return_value=None) as mocked: self.bot.add_participant('*****@*****.**') mocked.assert_called_with(id='*id', is_moderator=False, person='*****@*****.**') def test_remove_participants(self): logging.info('*** remove_participants ***') self.bot.channel = self.channel with mock.patch.object(self.bot.space, 'remove_participants', return_value=None) as mocked: self.bot.remove_participants(['a', 'b', 'c', 'd']) mocked.assert_called_with(id='*id', persons=['a', 'b', 'c', 'd']) def test_remove_participant(self): logging.info('*** remove_participant ***') self.bot.channel = self.channel with mock.patch.object(self.bot.space, 'remove_participant', return_value=None) as mocked: self.bot.remove_participant('*****@*****.**') mocked.assert_called_with(id='*id', person='*****@*****.**') def test_say(self): logging.info('*** say ***') self.bot.say('*not*said*because*not*ready') self.bot.channel = self.channel self.bot.say('') self.bot.say(None) with mock.patch.object(self.engine.mouth, 'put', return_value=None) as mocked: self.bot.say('test') self.bot.say('test', content='test') self.bot.say('test', file='test.yaml') self.bot.say('test', person='*****@*****.**') self.bot.say('test', content='test', person='*****@*****.**') self.bot.say('test', file='test.yaml', person='*****@*****.**') message_0 = None self.bot.say(message_0) with self.assertRaises(Exception): self.engine.mouth.get_nowait() message_0 = '' self.bot.say(message_0) with self.assertRaises(Exception): self.engine.mouth.get_nowait() message_1 = 'hello' self.bot.say(message_1) item = self.engine.mouth.get() self.assertEqual(item.text, message_1) self.assertEqual(item.channel_id, self.bot.id) self.assertEqual(item.person, None) self.bot.say(message_1, person='*****@*****.**') item = self.engine.mouth.get() self.assertEqual(item.text, message_1) self.assertEqual(item.channel_id, None) self.assertEqual(item.person, '*****@*****.**') message_2 = 'world' self.bot.say(message_2) self.assertEqual(self.engine.mouth.get().text, message_2) message_3 = 'hello' content_3 = 'world' self.bot.say(message_3, content=content_3) item = self.engine.mouth.get() self.assertEqual(item.text, message_3) self.assertEqual(item.content, content_3) self.assertEqual(item.file, None) message_4 = "What'sup Doc?" file_4 = 'http://some.server/some/file' self.bot.say(message_4, file=file_4) item = self.engine.mouth.get() self.assertEqual(item.text, message_4) self.assertEqual(item.content, None) self.assertEqual(item.file, file_4) message_5 = 'hello' content_5 = 'world' file_5 = 'http://some.server/some/file' self.bot.say(message_5, content=content_5, file=file_5) item = self.engine.mouth.get() self.assertEqual(item.text, message_5) self.assertEqual(item.content, content_5) self.assertEqual(item.file, file_5) content_6 = 'life is *good*' file_6 = 'http://some.server/some/file' self.bot.say(content=content_6, file=file_6) item = self.engine.mouth.get() self.assertEqual(item.text, None) self.assertEqual(item.content, content_6) self.assertEqual(item.file, file_6) content_7 = 'life is _very_ *good*' self.bot.say(content=content_7) item = self.engine.mouth.get() self.assertEqual(item.text, None) self.assertEqual(item.content, content_7) self.assertEqual(item.file, None) def test_say_banner(self): logging.info("*** say_banner") self.bot.channel = self.channel # banner settings have not been defined at all self.context.set('bot.banner.text', None) self.context.set('bot.banner.content', None) self.context.set('bot.banner.file', None) self.bot.say_banner() with self.assertRaises(Exception): self.engine.mouth.get_nowait() # banner settings are empty strings self.context.set('bot.banner.text', '') self.context.set('bot.banner.content', '') self.context.set('bot.banner.file', '') self.bot.say_banner() with self.assertRaises(Exception): self.engine.mouth.get_nowait() # plain banner with text, rich content, and some document upload self.context.set('bot.banner.text', u"Type '@{} help' for more information") self.context.set('bot.banner.content', u"Type ``@{} help`` for more information") self.context.set('bot.banner.file', "http://on.line.doc/guide.pdf") self.bot.say_banner() item = self.engine.mouth.get() self.assertEqual(item.text, "Type '@Shelly help' for more information") self.assertEqual(item.content, 'Type ``@Shelly help`` for more information') self.assertEqual(item.file, 'http://on.line.doc/guide.pdf') with self.assertRaises(Exception): self.engine.mouth.get_nowait() def test_remember(self): logging.info('***** remember') self.assertEqual(self.bot.recall('sca.lar'), None) self.bot.remember('sca.lar', 'test') self.assertEqual(self.bot.recall('sca.lar'), 'test') self.assertEqual(self.bot.recall('list'), None) self.bot.remember('list', ['hello', 'world']) self.assertEqual(self.bot.recall('list'), ['hello', 'world']) self.assertEqual(self.bot.recall('dict'), None) self.bot.remember('dict', {'hello': 'world'}) self.assertEqual(self.bot.recall('dict'), {'hello': 'world'}) def test_recall(self): logging.info('***** recall') # undefined key self.assertEqual(self.bot.recall('hello'), None) # undefined key with default value whatever = 'whatever' self.assertEqual(self.bot.recall('hello', whatever), whatever) # set the key self.bot.remember('hello', 'world') self.assertEqual(self.bot.recall('hello'), 'world') # default value is meaningless when key has been set self.assertEqual(self.bot.recall('hello', 'whatever'), 'world') # except when set to None self.bot.remember('special', None) self.assertEqual(self.bot.recall('special', []), []) def test_forget(self): logging.info('***** forget') # set the key and then forget it self.bot.remember('hello', 'world') self.assertEqual(self.bot.recall('hello'), 'world') self.bot.forget('hello') self.assertEqual(self.bot.recall('hello'), None) # set multiple keys and then forget all of them self.bot.remember('hello', 'world') self.bot.remember('bunny', "What'up, Doc?") self.assertEqual(self.bot.recall('hello'), 'world') self.assertEqual(self.bot.recall('bunny'), "What'up, Doc?") self.bot.forget() self.assertEqual(self.bot.recall('hello'), None) self.assertEqual(self.bot.recall('bunny'), None) def test_append(self): logging.info('***** append') self.bot.append('famous', 'hello, world') self.bot.append('famous', "What'up, Doc?") self.assertEqual(self.bot.recall('famous'), ['hello, world', "What'up, Doc?"]) def test_update(self): logging.info('***** update') self.bot.update('input', 'PO#', '1234A') self.bot.update('input', 'description', 'part does not fit') self.assertEqual(self.bot.recall('input'), { u'PO#': u'1234A', u'description': u'part does not fit' })
class BusTests(unittest.TestCase): def setUp(self): self.context = Context() self.context.set('general.switch', 'on') self.context.set('bus.address', 'tcp://127.0.0.1:6666') self.bus = Bus(context=self.context) def tearDown(self): del self.bus del self.context collected = gc.collect() if collected: logging.info("Garbage collector: collected %d objects." % (collected)) def test_bus_init(self): logging.info(u"***** bus/init") self.assertEqual(self.bus.DEFAULT_ADDRESS, 'tcp://127.0.0.1:5555') self.assertEqual(self.bus.context, self.context) def test_bus_check(self): logging.info(u"***** bus/check") self.context.set('bus.address', None) self.bus.check() self.assertEqual(self.context.get('bus.address'), self.bus.DEFAULT_ADDRESS) def test_bus_subscribe(self): logging.info(u"***** bus/subscribe") with self.assertRaises(AssertionError): subscriber = self.bus.subscribe(None) with self.assertRaises(AssertionError): subscriber = self.bus.subscribe([]) with self.assertRaises(AssertionError): subscriber = self.bus.subscribe(()) subscriber = self.bus.subscribe('channel') def test_bus_publish(self): logging.info(u"***** bus/publish") publisher = self.bus.publish() def test_subscriber_init(self): logging.info(u"***** subscriber/init") subscriber = Subscriber(context=self.context, channels='channel') self.assertEqual(subscriber.context, self.context) self.assertTrue(subscriber.socket is None) def test_subscriber_get(self): logging.info(u"***** subscriber/get") subscriber = self.bus.subscribe('dummy') subscriber.socket = mock.Mock() with mock.patch.object( subscriber.socket, 'recv', return_value='dummy {"hello": "world"}') as mocked: message = subscriber.get() self.assertEqual(message, {u'hello': u'world'}) def test_publisher_init(self): logging.info(u"***** publisher/init") publisher = Publisher(context=self.context) self.assertEqual(publisher.context, self.context) self.assertTrue(publisher.socket is None) def test_publisher_run(self): logging.info(u"***** publisher/run") publisher = Publisher(context=self.context) self.context.set('general.switch', 'off') publisher.run() self.context.set('general.switch', 'on') publisher.put('*weird', '*message') publisher.fan.put(None) publisher.run() def test_publisher_static_test(self): logging.info(u"***** publisher/static test") publisher = Publisher(context=self.context) publisher.DEFER_DURATION = 0.0 self.context.set('general.switch', 'on') publisher.start() publisher.join(0.1) if publisher.is_alive(): logging.info('Stopping publisher') self.context.set('general.switch', 'off') publisher.join() self.assertFalse(publisher.is_alive()) self.assertEqual(self.context.get('publisher.counter', 0), 0) def test_publisher_dynamic_test(self): logging.info(u"***** publisher/dynamic test") publisher = Publisher(context=self.context) self.context.set('general.switch', 'on') items = [ ('channel_A', "hello"), ('channel_B', "world"), ('channel_C', { "hello": "world" }), ] for (channel, message) in items: publisher.put(channel, message) publisher.fan.put(None) class MySocket(object): def __init__(self, context): self.context = context def send_string(self, item): pipe = self.context.get('pipe', []) pipe.append(item) self.context.set('pipe', pipe) def close(self): pass publisher.socket = MySocket(self.context) publisher.run() self.assertEqual(self.context.get('publisher.counter', 0), 3) self.assertEqual(self.context.get('pipe'), [ 'channel_A "hello"', 'channel_B "world"', 'channel_C {"hello": "world"}' ]) def test_publisher_put(self): logging.info(u"***** publisher/put") publisher = self.bus.publish() with self.assertRaises(AssertionError): publisher.put(None, 'message') with self.assertRaises(AssertionError): publisher.put('', 'message') with self.assertRaises(AssertionError): publisher.put([], 'message') with self.assertRaises(AssertionError): publisher.put((), 'message') with self.assertRaises(AssertionError): publisher.put('channel', None) with self.assertRaises(AssertionError): publisher.put('channel', '') with mock.patch.object(publisher.fan, 'put') as mocked: publisher.put('channel', 'message') mocked.assert_called_with('channel "message"') publisher.put(['channel'], 'message') mocked.assert_called_with('channel "message"') def test_life_cycle(self): logging.info(u"***** life cycle") class Listener(Process): def __init__(self, bus): Process.__init__(self) self.daemon = True self.bus = bus def run(self): subscriber = self.bus.subscribe('') logging.info(u"Starting subscriber") while self.bus.context.get('general.switch', 'off') == 'on': message = subscriber.get() if not message: time.sleep(0.001) continue self.bus.context.set('received', message) logging.info(u"- {}".format(message)) logging.info(u"Stopping subscriber") listener = Listener(self.bus) listener.start() publisher = self.bus.publish() publisher.start() for value in range(1, 10): publisher.put('channel', {'counter': value}) publisher.fan.put(None) publisher.join() time.sleep(0.5) self.bus.context.set('general.switch', 'off') time.sleep(0.5) listener.join()
class SparkSpaceTests(unittest.TestCase): def setUp(self): self.context = Context() self.ears = Queue() self.fan = Queue() self.space = SparkSpace(context=self.context, ears=self.ears, fan=self.fan) def tearDown(self): del self.space del self.fan del self.ears del self.context collected = gc.collect() if collected: logging.info("Garbage collector: collected %d objects." % (collected)) def test_on_init(self): logging.info("*** on_init") self.assertEqual(self.space.context.get('space.token'), None) self.assertEqual(self.space.api, None) self.assertEqual(self.space._last_message_id, 0) space = SparkSpace(context=self.context, token='b') self.assertEqual(space.context.get('space.token'), 'b') def test_configure(self): logging.info("*** configure") settings = { # from settings to member attributes 'space': { 'type': 'spark', 'room': 'My preferred room', 'participants': ['*****@*****.**', '*****@*****.**'], 'token': 'hkNWEtMJNkODVGlZWU1NmYtyY', } } self.space.configure(settings=settings) self.assertEqual(self.space.context.get('space.room'), 'My preferred room') self.assertEqual(self.space.configured_title(), 'My preferred room') self.assertEqual(self.space.context.get('space.participants'), ['*****@*****.**', '*****@*****.**']) self.assertEqual(self.space.context.get('space.token'), 'hkNWEtMJNkODVGlZWU1NmYtyY') self.space.context.clear() self.space.configure({ 'space': { 'type': 'spark', 'room': 'My preferred room', 'participants': '*****@*****.**', } }) self.assertEqual(self.space.context.get('space.room'), 'My preferred room') self.assertEqual(self.space.context.get('space.participants'), ['*****@*****.**']) with self.assertRaises(KeyError): # missing key self.space.context.clear() self.space.configure({ 'spark': { 'participants': ['*****@*****.**', '*****@*****.**'], 'team': 'Anchor team', 'token': 'hkNWEtMJNkODk3ZDZLOGQ0OVGlZWU1NmYtyY', } }) def test_connect(self): logging.info("*** connect") def my_factory(access_token): return FakeApi(access_token=access_token) self.space.context.set('space.token', None) with self.assertRaises(AssertionError): self.space.connect() self.space.context.set('space.token', 'a') self.space.connect(factory=my_factory) self.assertEqual(self.space.api.token, 'a') self.assertEqual(self.space.audit_api, None) self.space.context.set('space.token', 'a') self.space.context.set('space.audit_token', 'b') self.space.connect(factory=my_factory) self.assertEqual(self.space.api.token, 'a') self.assertEqual(self.space.audit_api.token, 'b') def test_on_connect(self): logging.info("*** on_connect") self.space.api = FakeApi(me=FakeBot()) self.space.on_connect() self.assertTrue(self.space.api.people.me.called) self.assertEqual(self.context.get('bot.address'), '*****@*****.**') self.assertEqual(self.context.get('bot.name'), 'shelly') self.assertTrue(len(self.context.get('bot.id')) > 20) def test_list_group_channels(self): logging.info("*** list_group_channels") self.space.api = FakeApi() channels = self.space.list_group_channels() self.assertEqual(len(channels), 1) self.assertTrue(self.space.api.rooms.list.called) channel = channels[0] self.assertEqual(channel.id, '*id') self.assertEqual(channel.title, '*title') def test_create(self): logging.info("*** create") with self.assertRaises(AssertionError): self.space.create(title=None) with self.assertRaises(AssertionError): self.space.create(title='') with self.assertRaises(AssertionError): self.space.create(title='*title') self.space.api = FakeApi() channel = self.space.create(title='*title') self.assertTrue(self.space.api.rooms.create.called) self.assertEqual(channel.id, '*id') self.assertEqual(channel.title, '*title') def test_get_by_title(self): logging.info("*** get_by_title") with self.assertRaises(AssertionError): channel = self.space.get_by_title(None) with self.assertRaises(AssertionError): channel = self.space.get_by_title('') with self.assertRaises(AssertionError): channel = self.space.get_by_title('*no*api*anyway') self.space.api = FakeApi() channel = self.space.get_by_title('*does*not*exist') self.assertEqual(channel, None) self.assertTrue(self.space.api.rooms.list.called) channel = self.space.get_by_title('*title') self.assertEqual( channel, Channel({ "id": "*id", "is_direct": False, "is_group": True, "is_moderated": True, "is_team": False, "team_id": "*team", "title": "*title", "type": "group", })) class Intruder(object): def list(self, **kwargs): raise Exception('TEST') self.space.api.rooms = Intruder() channel = self.space.get_by_title('*title') self.assertEqual(channel, None) def test_get_by_id(self): logging.info("*** get_by_id") with self.assertRaises(AssertionError): channel = self.space.get_by_id(None) with self.assertRaises(AssertionError): channel = self.space.get_by_id('') with self.assertRaises(AssertionError): channel = self.space.get_by_id('*no*api*anyway') self.space.api = FakeApi() channel = self.space.get_by_id('*id') self.assertEqual( channel, Channel({ "id": "*id", "is_direct": False, "is_group": True, "is_moderated": True, "is_team": False, "team_id": "*team", "title": "*title", "type": "group", })) class Intruder(object): def get(self, label, **kwargs): raise Exception('TEST') self.space.api.rooms = Intruder() channel = self.space.get_by_id('*id') self.assertEqual(channel, None) def test_get_by_person(self): logging.info("*** get_by_person") with self.assertRaises(AssertionError): channel = self.space.get_by_person(None) with self.assertRaises(AssertionError): channel = self.space.get_by_person('') with self.assertRaises(AssertionError): channel = self.space.get_by_person('*no*api*anyway') self.space.api = FakeApi(room=FakeDirectRoom()) channel = self.space.get_by_person('Marcel Jones') self.assertEqual( channel, Channel({ "id": "*direct_id", "is_direct": True, "is_group": False, "is_moderated": False, "is_team": False, "team_id": None, "title": "Marcel Jones", "type": "direct", })) class Intruder(object): def list(self, **kwargs): raise Exception('TEST') self.space.api.rooms = Intruder() channel = self.space.get_by_person('Marcel Jones') self.assertEqual(channel, None) def test_update(self): logging.info("*** update") self.space.api = FakeApi() self.space.update(channel=FakeChannel()) def test_delete(self): logging.info("*** delete") # explicit id, room exists self.space.api = FakeApi() self.space.delete(id='*id') self.assertTrue(self.space.api.rooms.delete.called) # explicit id, room does not exists self.space.api = FakeApi() self.space.delete(id='*ghost*room') self.assertTrue(self.space.api.rooms.delete.called) def test_get_team(self): logging.info("*** get_team") class Team(object): name = '*name' id = '456' self.space.api = FakeApi(teams=[Team()]) team = self.space.get_team(name='*name') self.assertTrue(self.space.api.teams.list.called) self.assertEqual(team.name, '*name') self.assertEqual(team.id, '456') self.space.api = FakeApi(teams=[Team()]) team = self.space.get_team(name='*unknown') self.assertTrue(self.space.api.teams.list.called) self.assertEqual(team, None) def test_list_participants(self): logging.info("*** list_participants") self.space.api = FakeApi() self.space.list_participants(id='*id') self.assertTrue(self.space.api.memberships.list.called) def test_add_participants(self): logging.info("*** add_participants") with mock.patch.object(self.space, 'add_participant') as mocked: self.space.add_participants(id='*id', persons=['*****@*****.**']) mocked.assert_called_with(id='*id', person='*****@*****.**') def test_add_participant(self): logging.info("*** add_participant") self.space.api = FakeApi() self.space.add_participant(id='*id', person='*****@*****.**') self.assertTrue(self.space.api.memberships.create.called) def test_remove_participants(self): logging.info("*** remove_participants") with mock.patch.object(self.space, 'remove_participant') as mocked: self.space.remove_participants(id='*id', persons=['*****@*****.**']) mocked.assert_called_with(id='*id', person='*****@*****.**') def test_remove_participant(self): logging.info("*** remove_participant") self.space.api = FakeApi() self.space.remove_participant(id='*id', person='*****@*****.**') self.assertTrue(self.space.api.memberships.delete.called) def test_post_message(self): logging.info("*** post_message") self.space.api = FakeApi() self.space.post_message(id='*id', text='hello world') self.assertTrue(self.space.api.messages.create.called) self.space.api = FakeApi() self.space.post_message(person='*****@*****.**', text='hello world') self.assertTrue(self.space.api.messages.create.called) self.space.api = FakeApi() self.space.post_message(id='*id', content='hello world') self.assertTrue(self.space.api.messages.create.called) self.space.api = FakeApi() self.space.post_message(person='*****@*****.**', content='hello world') self.assertTrue(self.space.api.messages.create.called) self.space.api = FakeApi() with self.assertRaises(AssertionError): self.space.post_message(text='hello world', content='hello world', file='./test_messages/sample.png') self.space.api = FakeApi() with self.assertRaises(AssertionError): self.space.post_message(id='*id', person='*****@*****.**', text='hello world', content='hello world', file='./test_messages/sample.png') self.space.api = FakeApi() self.space.post_message(id='*id', text='hello world', content='hello world', file='./test_messages/sample.png') self.assertTrue(self.space.api.messages.create.called) self.space.api = FakeApi() self.space.post_message(person='*****@*****.**', text='hello world', content='hello world', file='./test_messages/sample.png') self.assertTrue(self.space.api.messages.create.called) def test_register(self): logging.info("*** register") self.context.set('bot.id', '*id') self.context.set('spark.token', '*token') self.space.api = FakeApi() self.space.register('*hook') self.assertTrue(self.space.api.webhooks.create.called) self.assertFalse(self.context.get('audit.has_been_armed')) self.space.api = FakeApi() self.space.audit_api = FakeApi() self.space.register('*hook') self.assertTrue(self.space.api.webhooks.create.called) self.assertTrue(self.context.get('audit.has_been_armed')) def test_deregister(self): logging.info("*** deregister") self.space.api = FakeApi() self.context.set('bot.id', '*id') self.space.deregister() self.assertTrue(self.space.api.webhooks.list.called) def test_run(self): logging.info("*** run") self.space.api = FakeApi() self.space.PULL_INTERVAL = 0.001 mocked = mock.Mock(return_value=[]) self.space.pull = mocked p = self.space.start() p.join(0.01) if p.is_alive(): logging.info('Stopping puller') self.context.set('general.switch', 'off') p.join() self.assertFalse(p.is_alive()) def test_webhook(self): logging.info("*** webhook") fake_message = { u'status': u'active', u'resource': u'messages', u'name': u'shellbot-messages', u'created': u'2017-07-30T20:14:24.050Z', u'appId': u'Y2lzY29zcGFyazovL3VzLmM3ZDUxNWNiNGEwY2M5MWFh', u'id': u'Y2lzY29zcGFyazovL3VzjI0MTM2ZjgwY2Yy', u'orgId': u'Y2lzY29zcGFyazovL3VYjU1ZS00ODYzY2NmNzIzZDU', u'createdBy': u'Y2lzY29zcGFyazovL3VzLS01ZGI5M2Y5MjI5MWM', u'targetUrl': u'http://0dab1.ngrok.io/hook', u'ownedBy': u'creator', u'actorId': u'Y2lzY29zcGFyazovL3VzL1BFkyMzU', u'data': { u'roomType': u'group', u'created': u'2017-07-30T20:14:50.882Z', u'personId': u'Y2lzY29zcGFyayYi1mYWYwZWQwMjkyMzU', u'personEmail': u'*****@*****.**', u'mentionedPeople': [u'Y2lzY29zcGFyazovL3VGI5M2Y5MjI5MWM'], u'roomId': u'Y2lzY29zcGFyazovL3VzL1NzUtYzc2ZDMyOGY0Y2Rj', u'id': '*123', }, u'event': u'created', } self.space.api = FakeApi() self.assertEqual(self.space.webhook(fake_message), 'OK') self.assertTrue(self.space.api.messages.get.called) data = self.space.ears.get() self.assertEqual( yaml.safe_load(data), { 'text': '*message', 'content': '*message', 'from_id': None, 'from_label': None, 'hook': 'shellbot-messages', 'stamp': '2017-07-19T05:29:23.962Z', 'created': '2017-07-19T05:29:23.962Z', 'channel_id': None, 'type': 'message', 'is_direct': False, 'mentioned_ids': [] }) with self.assertRaises(Exception): print(self.space.ears.get_nowait()) with self.assertRaises(Exception): print(self.space.fan.get_nowait()) fake_message = { u'status': u'active', u'resource': u'messages', u'name': u'shellbot-audit', u'created': u'2017-07-30T20:25:29.924Z', u'appId': u'Y2lzY29zcGFyazovL3VzL0FQUE2YyNjZhYmY2NmM5OTllYzFm', u'id': u'Y2lzY29zcGFyazovL3VzL1dFC00NzllLTg0MDQtZGQ2NGJiNTk3Nzdi', u'orgId': u'Y2lzY29zcGFyazovL3VzL09SR0FOSVpBVY2NmNzIzZDU', u'createdBy': u'Y2lzY29zcGFyazovL3VzL1BFTTIyYi1mYWYwZWQwMjkyMzU', u'targetUrl': u'http://0dab1.ngrok.io/hook', u'ownedBy': u'creator', u'actorId': u'Y2lzY29zcGFyazovL3VzLM2Y5MjI5MWM', u'data': { u'files': [u'http://hydra-a5.wbx2.com/contents/Y2lzY29zcGFWY5LzA'], u'roomType': u'group', u'created': u'2017-07-30T20:25:33.803Z', u'personId': u'Y2lzY29zcGFyazovL3VzL1BFT5M2Y5MjI5MWM', u'personEmail': u'*****@*****.**', u'roomId': u'Y2lzY29zcGFyazovL3VzL1JPTyNmFhNWYxYTY4', u'id': u'*123', }, u'event': u'created', } self.space.audit_api = FakeApi() self.assertEqual(self.space.webhook(fake_message), 'OK') self.assertTrue(self.space.audit_api.messages.get.called) data = self.space.fan.get() self.assertEqual( yaml.safe_load(data), { 'text': '*message', 'content': '*message', 'from_id': None, 'from_label': None, 'hook': 'shellbot-audit', 'stamp': '2017-07-19T05:29:23.962Z', 'created': '2017-07-19T05:29:23.962Z', 'channel_id': None, 'type': 'message', 'is_direct': False, 'mentioned_ids': [] }) with self.assertRaises(Exception): print(self.space.ears.get_nowait()) with self.assertRaises(Exception): print(self.space.fan.get_nowait()) def test_pull(self): logging.info("*** pull") self.space.api = FakeApi(messages=[FakeMessage()]) self.assertEqual(self.space._last_message_id, 0) self.space.pull() self.assertEqual(self.context.get('puller.counter'), 1) self.assertTrue(self.space.api.messages.list.called) self.assertEqual(self.space._last_message_id, '*123') self.space.pull() self.assertEqual(self.context.get('puller.counter'), 2) self.assertEqual(self.space._last_message_id, '*123') self.space.pull() self.assertEqual(self.context.get('puller.counter'), 3) self.assertEqual(self.space._last_message_id, '*123') self.assertEqual( yaml.safe_load(self.ears.get()), { 'text': '*message', 'content': '*message', 'from_id': None, 'from_label': None, 'hook': 'pull', 'stamp': '2017-07-19T05:29:23.962Z', 'created': '2017-07-19T05:29:23.962Z', 'channel_id': None, 'type': 'message', 'is_direct': False, 'mentioned_ids': [] }) with self.assertRaises(Exception): print(self.ears.get_nowait()) def test_on_message(self): logging.info("*** on_message") class MySpace(SparkSpace): def name_attachment(self, url, token=None): return 'some_file.pdf' def get_attachment(self, url, token=None): return b'hello world' self.space = MySpace(context=self.context) self.space.on_message(my_message, self.ears) message = my_message.copy() message.update({"type": "message"}) message.update({"content": message['text']}) message.update({"attachment": "some_file.pdf"}) message.update({"url": "http://www.example.com/images/media.png"}) message.update({"from_id": '*matt*id'}) message.update({"from_label": '*****@*****.**'}) message.update({'is_direct': False}) message.update({"mentioned_ids": ['*matt*id', '*julie*id']}) message.update({"channel_id": '*id1'}) message.update({"stamp": '2015-10-18T14:26:16+00:00'}) self.maxDiff = None self.assertEqual(yaml.safe_load(self.ears.get()), message) self.space.on_message(my_private_message, self.ears) message = my_private_message.copy() message.update({"type": "message"}) message.update({"content": message['text']}) message.update({"from_id": '*foo*id'}) message.update({"from_label": '*****@*****.**'}) message.update({'is_direct': True}) message.update({"mentioned_ids": []}) message.update({"channel_id": '*direct*id'}) message.update({"stamp": '2017-07-22T16:49:22.008Z'}) self.maxDiff = None self.assertEqual(yaml.safe_load(self.ears.get()), message) with self.assertRaises(Exception): print(self.ears.get_nowait()) def test_download_attachment(self): logging.info("*** download_attachment") class MySpace(SparkSpace): def name_attachment(self, url, token=None): return 'some_file.pdf' def get_attachment(self, url, token=None): return BytesIO(b'hello world') space = MySpace(context=self.context) outcome = space.download_attachment(url='/dummy') with open(outcome, "rb") as handle: self.assertEqual(handle.read(), space.get_attachment('/dummy').read()) try: os.remove(outcome) except: pass def test_name_attachment(self): logging.info("*** name_attachment") class MyResponse(object): def __init__(self, status_code=200, headers={}): self.status_code = status_code self.headers = headers self.space.token = None response = MyResponse(headers={'Content-Disposition': 'who cares'}) self.assertEqual( self.space.name_attachment(url='/dummy', response=response), 'downloadable') self.space.token = '*void' response = MyResponse( headers={'Content-Disposition': 'filename="some_file.pdf"'}) self.assertEqual( self.space.name_attachment(url='/dummy', response=response), 'some_file.pdf') self.space.token = None response = MyResponse( status_code=400, headers={'Content-Disposition': 'filename="some_file.pdf"'}) with self.assertRaises(Exception): name = self.space.name_attachment(url='/dummy', response=response) def test_get_attachment(self): logging.info("*** get_attachment") class MyResponse(object): def __init__(self, status_code=200, headers={}): self.status_code = status_code self.headers = headers self.encoding = 'encoding' self.content = b'content' self.space.token = None response = MyResponse(headers={}) content = self.space.get_attachment(url='/dummy', response=response).getvalue() self.assertEqual(content, b'content') self.space.token = '*void' response = MyResponse(headers={}) content = self.space.get_attachment(url='/dummy', response=response).getvalue() self.assertEqual(content, b'content') self.space.token = None response = MyResponse(status_code=400, headers={}) with self.assertRaises(Exception): content = self.space.get_attachment(url='/dummy', response=response) def test_on_join(self): logging.info("*** on_join") self.space.on_join(my_join, self.ears) item = my_join.copy() item.update({"type": "join"}) item.update( {"actor_id": 'Y2lzY29zcGFyazovL3VRiMTAtODZkYy02YzU0Yjg5ODA5N2U'}) item.update({"actor_address": '*****@*****.**'}) item.update({"actor_label": 'Foo Bar'}) item.update({ "channel_id": 'Y2lzY29zcGFyazovL3VzL1JP3LTk5MDAtMDU5MDI2YjBiNDUz' }) item.update({"stamp": '2017-05-31T21:25:30.424Z'}) self.maxDiff = None self.assertEqual(yaml.safe_load(self.ears.get()), item) def test_on_leave(self): logging.info("*** on_leave") self.space.on_leave(my_leave, self.ears) item = my_leave.copy() item.update({"type": "leave"}) item.update( {"actor_id": 'Y2lzY29zcGFyazovL3VRiMTAtODZkYy02YzU0Yjg5ODA5N2U'}) item.update({"actor_address": '*****@*****.**'}) item.update({"actor_label": 'Foo Bar'}) item.update({ "channel_id": 'Y2lzY29zcGFyazovL3VzL1JP3LTk5MDAtMDU5MDI2YjBiNDUz' }) item.update({"stamp": '2017-05-31T21:25:30.424Z'}) self.maxDiff = None self.assertEqual(yaml.safe_load(self.ears.get()), item) def test__to_channel(self): logging.info("*** _to_channel") channel = self.space._to_channel(FakeRoom()) self.assertEqual(channel.id, '*id') self.assertEqual(channel.title, '*title') self.assertFalse(channel.is_direct) self.assertTrue(channel.is_group) self.assertFalse(channel.is_team) self.assertTrue(channel.is_moderated) channel = self.space._to_channel(FakeDirectRoom()) self.assertEqual(channel.id, '*direct_id') self.assertEqual(channel.title, 'Marcel Jones') self.assertTrue(channel.is_direct) self.assertFalse(channel.is_group) self.assertFalse(channel.is_team) self.assertFalse(channel.is_moderated) channel = self.space._to_channel(FakeTeamRoom()) self.assertEqual(channel.id, '*team_id') self.assertEqual(channel.title, '*team_title') self.assertFalse(channel.is_direct) self.assertTrue(channel.is_group) self.assertTrue(channel.is_team) self.assertFalse(channel.is_moderated)