def setUp(self): self.context = Context(settings=my_settings) self.engine = Engine(context=self.context, mouth=Queue()) self.engine.factory = TodoFactory(self.engine.get('todos.items', [])) self.engine.bus = Bus(self.context) self.engine.bus.check() self.engine.publisher = self.engine.bus.publish() self.bot = self.engine.get_bot()
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_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"))
class EmptyTests(unittest.TestCase): def setUp(self): self.engine = Engine(mouth=Queue()) self.engine.configure() self.engine.shell = Shell(engine=self.engine) self.bot = MyBot(engine=self.engine) def tearDown(self): collected = gc.collect() if collected: logging.info("Garbage collector: collected %d objects." % (collected)) def test_init(self): logging.info('***** init') c = Empty(self.engine) self.assertEqual(c.keyword, u'*empty') self.assertEqual(c.information_message, u'Handle empty command') self.assertEqual(c.usage_message, None) self.assertTrue(c.is_hidden) def test_execute(self): logging.info('***** execute') self.engine.shell.load_command('shellbot.commands.help') c = Empty(self.engine) c.execute(self.bot) self.assertEqual( self.engine.mouth.get().text, u'Available commands:\nhelp - Show commands and usage') with self.assertRaises(Exception): print(self.engine.mouth.get_nowait()) c = Empty(self.engine) self.engine.shell._commands = {} c.execute(self.bot) self.assertEqual(self.engine.mouth.get().text, u'No help command has been found.') with self.assertRaises(Exception): print(self.engine.mouth.get_nowait())
def setUp(self): self.context = Context() self.engine = Engine(context=self.context, mouth=Queue()) self.space = LocalSpace(context=self.context, ears=self.engine.ears) self.store = MemoryStore(context=self.context) self.machine = MyMachine() self.bot = MyBot(engine=self.engine) self.bot.machine = None
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'})
class UploadTests(unittest.TestCase): def setUp(self): self.engine = Engine(mouth=Queue()) self.engine.configure() self.engine.shell = Shell(engine=self.engine) self.bot = MyBot(engine=self.engine) def tearDown(self): del self.bot del self.engine collected = gc.collect() if collected: logging.info("Garbage collector: collected %d objects." % (collected)) def test_init(self): logging.info('***** init') c = Upload(self.engine) self.assertEqual(c.keyword, u'*upload') self.assertEqual(c.information_message, u'Handle file upload') self.assertEqual(c.usage_message, None) self.assertTrue(c.is_hidden) def test_execute(self): logging.info('***** execute') c = Upload(self.engine) c.execute(self.bot, url='http://from/here', attachment='picture.png') self.assertEqual(self.engine.mouth.get().text, u'Thank you for the information shared!') with self.assertRaises(Exception): print(self.engine.mouth.get_nowait())
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)
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')
}, { 'label': u'Terminated', 'message': u'Process is closed, yet conversation can continue', }, ], } context = Context(settings) context.check('server.trigger', '/trigger') context.check('server.hook', '/hook') engine = Engine( # use Cisco Spark and setup the environment type='spark', context=context, configure=True, commands=['shellbot.commands.step', 'shellbot.commands.close'], machine_factory=MyFactory(steps=context.get('process.steps')), ears=Queue(), ) server = Server(context=context, check=True) # set web front-end server.add_route( Notifier(queue=engine.ears, notification={ 'type': 'event', 'trigger': 'click' }, route=context.get('server.trigger'))) server.add_route(
#!/usr/bin/env python # -*- coding: utf-8 -*- import unittest import logging import mock from multiprocessing import Process, Queue import os import sys from shellbot import Context, Engine, Shell, Vibes from shellbot.commands import Command my_engine = Engine(mouth=Queue()) my_engine.shell = Shell(engine=my_engine) class Bot(object): def __init__(self, engine): self.engine = engine def say(self, text, content=None, file=None): self.engine.mouth.put(Vibes(text, content, file)) my_bot = Bot(engine=my_engine) class BaseTests(unittest.TestCase): def test_init(self):
direct_channel = self.engine.space.get_by_person(received.actor_label) if direct_channel: direct_bot = self.engine.get_bot(direct_channel.id) if direct_bot.machine and not direct_bot.machine.is_running: direct_bot.machine.restart() def on_leave(self, received): print("LEAVE: {}".format(received)) bot = self.engine.get_bot(received.channel_id) bot.say(u"Bye bye '{}', we will miss you in '{}'".format( received.actor_label, bot.title)) if __name__ == '__main__': Context.set_logger() engine = Engine(type='spark', command='shellbot.commands.input', machine_factory=MyFactory()) os.environ['CHAT_ROOM_TITLE'] = '*dummy' engine.configure() handler = Handler(engine) engine.register('enter', handler) engine.register('exit', handler) engine.register('join', handler) engine.register('leave', handler) engine.run()
class ObserverTests(unittest.TestCase): def setUp(self): self.fan = Queue() self.engine = Engine(updater_factory=FakeFactory(), fan=self.fan) self.engine.set('bots.ids', ['*id1']) def tearDown(self): del self.engine del self.fan collected = gc.collect() if collected: logging.info("Garbage collector: collected %d objects." % (collected)) def test_static(self): logging.info('*** Static test ***') observer = Observer(engine=self.engine) observer.start() observer.join(0.1) if observer.is_alive(): logging.info('Stopping observer') self.engine.set('general.switch', 'off') observer.join() self.assertFalse(observer.is_alive()) self.assertEqual(self.engine.get('observer.counter', 0), 0) def test_dynamic(self): logging.info('*** Dynamic test ***') self.engine.fan.put(my_message) self.engine.fan.put(None) observer = Observer(engine=self.engine) observer.run() with self.assertRaises(Exception): engine.fan.get_nowait() def test_start(self): logging.info("*** start") self.engine.fan.put(my_message) self.engine.set('general.switch', 'on') self.engine.set('observer.counter', 0) # do not wait for run() observer = Observer(engine=self.engine) observer.start() while True: counter = self.engine.get('observer.counter', 0) if counter > 0: logging.info("- observer.counter > 0") break self.engine.set('general.switch', 'off') observer.join() self.assertTrue(self.engine.get('observer.counter') > 0) def test_run(self): logging.info("*** run") self.engine.observer.process = mock.Mock(side_effect=Exception('TEST')) self.engine.fan.put(my_message) self.engine.fan.put(None) self.engine.observer.run() self.assertEqual(self.engine.get('observer.counter'), 0) self.engine.observer = Observer(engine=self.engine) self.engine.observer.process = mock.Mock( side_effect=KeyboardInterrupt('ctl-C')) self.engine.fan.put(my_message) self.engine.observer.run() self.assertEqual(self.engine.get('observer.counter'), 0) def test_run_wait(self): logging.info("*** run/wait while empty") self.engine.observer.NOT_READY_DELAY = 0.01 self.engine.set('general.switch', 'on') self.engine.observer.start() t = Timer(0.1, self.engine.fan.put, [my_message]) t.start() time.sleep(0.2) self.engine.set('general.switch', 'off') self.engine.observer.join() def test_process(self): logging.info('*** process ***') self.engine.set('audit.switch.*id1', 'on') observer = Observer(engine=self.engine) observer.process(my_message) updater = observer.updaters['*id1'] self.assertEqual(updater.count, 2) # because of self-generated msg self.assertEqual(updater.text, 'hello world') self.engine.set('audit.switch.*id1', 'off') observer.process(my_message) self.assertEqual(updater.count, 3) # because of self-generated msg self.assertEqual(updater.text, '========== AUDIT OFF ==========') observer.process(my_01_message_from_bot_in_group) observer.process(my_03_message_from_person_in_group) observer.process(my_04_response_from_bot_in_group) observer.process(my_05_message_out_of_scope_for_audit) self.assertEqual(updater.count, 3) self.assertEqual(updater.text, '========== AUDIT OFF ==========') self.engine.set('audit.switch.*id1', 'on') observer.process(my_01_message_from_bot_in_group) self.assertEqual(updater.count, 5) # because of self-generated msg self.assertEqual(updater.text, "Type '@shelly help' for more information") observer.process(my_03_message_from_person_in_group) self.assertEqual(updater.count, 6) self.assertEqual(updater.text, 'shelly hello') observer.process(my_04_response_from_bot_in_group) self.assertEqual(updater.count, 7) self.assertEqual(updater.text, 'Hello, World!') observer.process(my_05_message_out_of_scope_for_audit) self.assertEqual(updater.count, 7) # not considered by observer
class DefaultTests(unittest.TestCase): def setUp(self): self.context = Context() self.engine = Engine(context=self.context, mouth=Queue()) self.engine.configure() self.bot = Bot(engine=self.engine) def tearDown(self): del self.bot 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") c = Default(self.engine) self.assertEqual(c.keyword, u'*default') self.assertEqual(c.information_message, u'Handle unmatched commands') self.assertEqual(c.usage_message, None) self.assertTrue(c.is_hidden) def test_execute_unknown(self): logging.info("***** execute unknown") c = Default(self.engine) c.execute(self.bot, '*unknown*') self.assertEqual(self.engine.mouth.get().text, u"Sorry, I do not know how to handle '*unknown*'") with self.assertRaises(Exception): self.engine.mouth.get_nowait() def test_execute_named_list(self): logging.info("***** execute named list") self.engine.configure_from_path( os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'test_settings', 'regular.yaml')) c = Default(self.engine) c.execute(self.bot, 'The Famous Four') # as_command not set self.assertEqual( self.engine.mouth.get().text, u"Sorry, I do not know how to handle 'The Famous Four'") with self.assertRaises(Exception): self.engine.mouth.get_nowait() class MyChannel(object): is_direct = True self.bot.channel = MyChannel() c.execute(self.bot, 'SupportTeam') # as_command in direct channel self.assertEqual(self.engine.mouth.get().text, u"Sorry, I do not know how to handle 'SupportTeam'") with self.assertRaises(Exception): self.engine.mouth.get_nowait() self.bot.channel.is_direct = False c.execute(self.bot, 'SupportTeam') # as_command in group channel self.assertEqual(self.engine.mouth.get().text, u"Adding participants from 'SupportTeam'") with self.assertRaises(Exception): self.engine.mouth.get_nowait() self.assertEqual(self.bot.participants, ['*****@*****.**', '*****@*****.**'])
def setUp(self): self.context = Context() self.engine = Engine(context=self.context, mouth=Queue()) self.engine.configure() self.bot = Bot(engine=self.engine)
from planets import PlanetFactory from planets.rocket import Rocket class FlyingBot(ShellBot): # add a rocket to each bot def on_init(self): self.rocket = Rocket(self) self.rocket.start() if __name__ == '__main__': Context.set_logger() engine = Engine( type='spark', # use Cisco Spark and setup flying envronment commands=PlanetFactory.commands(), driver=FlyingBot) os.environ['BOT_ON_ENTER'] = 'Hello Buzz, welcome to Cape Canaveral' os.environ['BOT_ON_EXIT'] = 'Batman is now quitting the room, bye' os.environ['CHAT_ROOM_TITLE'] = 'Buzz flights' engine.configure() # ensure that all components are ready engine.set('bot.store.planets', [ 'Mercury', 'Venus', 'Moon', 'Mars', 'Jupiter', 'Saturn', 'Uranus',
thanks_content = u"Thanks for the upload of `{}`" def execute(self, bot, arguments=None, attachment=None, url=None, **kwargs): bot.say(content=self.feedback_content.format( arguments if arguments else 'World')) if attachment: bot.say(content=self.thanks_content.format(attachment)) if __name__ == '__main__': Context.set_logger() engine = Engine(type='spark', command=Hello()) os.environ['CHAT_ROOM_TITLE'] = 'Hello tutorial' os.environ['BOT_BANNER_TEXT'] = u"Type '@{} help' for more information" os.environ['BOT_BANNER_CONTENT'] = (u"Hello there! " u"Type ``@{} help`` at any time " u"and get more information " u"on available commands.") os.environ['BOT_BANNER_FILE'] = \ "http://skinali.com.ua/img/gallery/19/thumbs/thumb_m_s_7369.jpg" engine.configure() # ensure that all components are ready engine.bond(reset=True) # create a group channel for this example engine.run() # until Ctl-C engine.dispose() # delete the initial group channel
def setUp(self): self.engine = Engine() self.store = MemoryStore() self.bot = ShellBot(engine=self.engine, store=self.store) self.raw_steps = [ { 'label': u'Level 1', 'message': u'Initial capture of information', 'content': u'**Initial** `capture` of _information_', 'file': "https://upload.wikimedia.org/wikipedia/en/c/c6/Bat-signal_1989_film.jpg", }, { 'label': u'Level 2', 'message': u'Escalation to technical experts', 'participants': '*****@*****.**', }, { 'label': u'Level 3', 'message': u'Escalation to decision stakeholders', 'participants': '*****@*****.**', }, { 'label': u'Terminated', 'message': u'Process is closed, yet conversation can continue', }, ] self.steps = [ Step( { 'label': u'Level 1', 'message': u'Initial capture of information', 'content': u'**Initial** `capture` of _information_', 'file': "https://upload.wikimedia.org/wikipedia/en/c/c6/Bat-signal_1989_film.jpg", }, 1), Step( { 'label': u'Level 2', 'message': u'Escalation to technical experts', 'participants': '*****@*****.**', 'machine': FakeMachine(running=False), }, 2), Step( { 'label': u'Level 3', 'message': u'Escalation to decision stakeholders', 'participants': '*****@*****.**', 'machine': FakeMachine(running=False), }, 3), Step( { 'label': u'Terminated', 'message': u'Process is closed, yet conversation can continue', 'machine': FakeMachine(running=False), }, 4), ] self.running_steps = [ Step( { 'label': u'Level 1', 'message': u'Initial capture of information', 'content': u'**Initial** `capture` of _information_', 'file': "https://upload.wikimedia.org/wikipedia/en/c/c6/Bat-signal_1989_film.jpg", }, 1), Step( { 'label': u'Level 2', 'message': u'Escalation to technical experts', 'participants': '*****@*****.**', 'machine': FakeMachine(running=True), }, 2), Step( { 'label': u'Level 3', 'message': u'Escalation to decision stakeholders', 'participants': '*****@*****.**', 'machine': FakeMachine(running=True), }, 3), Step( { 'label': u'Terminated', 'message': u'Process is closed, yet conversation can continue', 'machine': FakeMachine(running=True), }, 4), ]
else: bot.say('Such a lovely place...') time.sleep(5) bot.add_participant(received.actor_address) bot.say((u"{}, you can check out any time you like, " u"but you can never leave!").format(received.actor_label), content=(u'<@personEmail:{}|{}>, you can **check out ' u'any time you like**, ' u'but you can **never** leave!').format( received.actor_address, received.actor_label)) if __name__ == '__main__': Context.set_logger() engine = Engine(type='spark', commands=[Open(), Close(), Hotel()]) os.environ['BOT_ON_ENTER'] = 'On a dark desert highway, cool wind in my hair...' os.environ['CHAT_ROOM_TITLE'] = 'Hotel California' engine.configure() # ensure that all components are ready magic = Magic(engine=engine) # monitor newcomers and leavers engine.register('join', magic) engine.register('leave', magic) engine.bond(reset=True) # create a group channel for this example engine.run() # until Ctl-C engine.dispose() # delete the initial group channel
class RocketTests(unittest.TestCase): def setUp(self): self.engine = Engine(mouth=Queue()) self.bot = ShellBot(engine=self.engine, channel_id='*id') self.rocket = MyRocket(bot=self.bot) def tearDown(self): del self.rocket del self.bot del self.engine collected = gc.collect() if collected: logging.info("Garbage collector: collected %d objects." % (collected)) def test_static(self): logging.info('*** Static test ***') rocket_process = self.rocket.start() rocket_process.join(0.01) if rocket_process.is_alive(): logging.info('Stopping rocket') self.engine.set('general.switch', 'off') rocket_process.join() self.assertFalse(rocket_process.is_alive()) def test_dynamic(self): logging.info('*** Dynamic test ***') self.rocket.inbox.put(('explore', 'Moon')) self.rocket.inbox.put(None) self.rocket.run() self.assertEqual(self.engine.get('processed'), ('explore', 'Moon')) with self.assertRaises(Exception): print(self.engine.mouth.get_nowait()) def test_run(self): logging.info("*** run") rocket = Rocket(bot=self.bot) rocket.process = mock.Mock(side_effect=Exception('TEST')) rocket.inbox.put(('explore', 'Moon')) rocket.inbox.put(None) rocket.run() self.engine.context.clear() rocket = Rocket(bot=self.bot) rocket.process = mock.Mock(side_effect=KeyboardInterrupt('ctl-C')) rocket.inbox.put(('explore', 'Moon')) rocket.run() def test_process(self): logging.info("*** process") rocket = Rocket(bot=self.bot) with self.assertRaises(AssertionError): rocket.process(('*unknwon_verb', 'Moon')) rocket.process(('explore', '*alien_planet')) self.assertEqual(self.engine.mouth.get().text, "Planet '*alien_planet' is unknown")
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 setUp(self): self.engine = Engine(mouth=Queue()) self.bot = ShellBot(engine=self.engine, channel_id='*id') self.rocket = MyRocket(bot=self.bot)
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
bot.say(self.information_message, file=self.information_file) class Batsuicide(Command): # a command only for group channels keyword = 'suicide' information_message = u"Go back to Hell" in_direct = False def execute(self, bot, arguments=None, **kwargs): bot.say(self.information_message) bot.dispose() if __name__ == '__main__': Context.set_logger() engine = Engine( # use Cisco Spark and load shell commands type='spark', commands=[Batman(), Batcave(), Batsignal(), Batsuicide()]) os.environ['BOT_ON_ENTER'] = 'You can now chat with Batman' os.environ['BOT_ON_EXIT'] = 'Batman is now quitting the room, bye' os.environ['CHAT_ROOM_TITLE'] = 'Chat with Batman' engine.configure() # ensure that all components are ready engine.bond(reset=True) # create a group channel for this example engine.run() # until Ctl-C engine.dispose() # delete the initial group channel
def setUp(self): self.fan = Queue() self.engine = Engine(updater_factory=FakeFactory(), fan=self.fan) self.engine.set('bots.ids', ['*id1'])
def setUp(self): self.engine = Engine(mouth=Queue()) self.engine.configure() self.engine.shell = Shell(engine=self.engine) self.bot = MyBot(engine=self.engine)
""" import logging from multiprocessing import Process, Queue import os from shellbot import Engine, Context from shellbot.updaters import FileUpdater class UpdaterFactory(object): # create one updater per group channel def get_updater(self, id): return FileUpdater(path='./updater-{}.log'.format(id)) if __name__ == '__main__': Context.set_logger() engine = Engine( # use Cisco Spark and setup audit environment type='spark', command='shellbot.commands.audit', updater_factory=UpdaterFactory()) os.environ['CHAT_ROOM_TITLE'] = 'Audit tutorial' engine.configure() # ensure all components are ready engine.bond(reset=True) # create a group channel for this example engine.run() # until Ctl-C engine.dispose() # delete the initial group channel
"because the sky is green.", "for a disease.", "to be able to make toast explode.", "to know more about archeology." ] return u"{} {} {} {}".format(random.choice(s_nouns), random.choice(s_verbs), random.choice(p_nouns).lower(), random.choice(infinitives)) if __name__ == '__main__': Context.set_logger() os.environ['CHAT_ROOM_TITLE'] = 'Notifications' engine = Engine(type='spark', configure=True) bot = engine.get_bot(reset=True) # create a group channel for index in range(7): # send notifications to the channel bot.say(some_message()) time.sleep(5) bot.say(u"Nothing more to say") print("Press Ctl-C to stop this program") try: while True: time.sleep(0.01) except KeyboardInterrupt: pass
# -*- coding: utf-8 -*- import unittest import gc import json import logging import mock from multiprocessing import Process, Queue import os import sys from shellbot import Context, Engine, ShellBot, Shell from shellbot.events import Message from shellbot.updaters import Updater my_engine = Engine() class BaseTests(unittest.TestCase): def tearDown(self): collected = gc.collect() logging.info("Garbage collector: collected %d objects." % (collected)) def test_init(self): logging.info('***** init') u = Updater() self.assertEqual(u.engine, None) def test_on_init(self):
interactions, and reproduce them at will. For example, if you run this script under Linux or macOs:: python hello_simulator.py """ import logging import os from shellbot import Engine, Context, Command class Hello(Command): keyword = 'hello' information_message = u"Hello, World!" if __name__ == '__main__': Context.set_logger(level=logging.INFO) engine = Engine(command=Hello(), type='local') engine.space.push(['help', 'hello', 'help help']) engine.configure() engine.run()