async def setUp(self) -> None: self.addr_db = InMemoryAddressBookDB() self.service = AddressBookService(self.addr_db) self.service.start() self.address_data = address_data_suite() for nickname, addr in self.address_data.items(): await self.addr_db.create_address(addr, nickname)
async def setUp(self) -> None: self.addr_db = InMemoryAddressBookDB() tracing.set_trace_collectors( [tracing.CummulativeFunctionTimeProfiler()]) self.service = AddressBookService(self.addr_db) self.service.start() self.address_data = address_data_suite() for nickname, addr in self.address_data.items(): await self.addr_db.create_address(addr, nickname)
def get_app(self) -> tornado.web.Application: # get_app is the hook that Tornado Test uses to get app under test addr_db = create_addressbook_db(TEST_CONFIG['addr-db']) addr_service = AddressBookService(addr_db) addr_service.start() atexit.register(lambda: addr_service.stop()) return make_addrservice_app(service=addr_service, config=TEST_CONFIG, debug=True)
async def setUp(self) -> None: logging.config.dictConfig(TEST_CONFIG['logging']) logger = logging.getLogger(LOGGER_NAME) self.service = AddressBookService(config=TEST_CONFIG, logger=logger) self.service.start() self.address_data = address_data_suite() for nickname, val in self.address_data.items(): addr = AddressEntry.from_api_dm(val) await self.service.addr_db.create_address(addr, nickname)
class AddressBookServiceWithInMemoryDBTest(asynctest.TestCase): async def setUp(self) -> None: self.addr_db = InMemoryAddressBookDB() tracing.set_trace_collectors( [tracing.CummulativeFunctionTimeProfiler()]) self.service = AddressBookService(self.addr_db) self.service.start() self.address_data = address_data_suite() for nickname, addr in self.address_data.items(): await self.addr_db.create_address(addr, nickname) async def tearDown(self) -> None: self.service.stop() def test_uptime(self) -> None: self.assertGreater(self.service.uptime_millis(), 0) @asynctest.fail_on(active_handles=True) async def test_status(self) -> None: status = await self.service.status() self.assertTrue(status['ready']) self.assertGreater(status['uptime'], 0) @asynctest.fail_on(active_handles=True) async def test_get_address(self) -> None: for nickname, addr in self.address_data.items(): value = await self.service.get_address(nickname) self.assertEqual(addr, value) @asynctest.fail_on(active_handles=True) async def test_get_all_addresses(self) -> None: all_addr = await self.service.get_all_addresses() self.assertEqual(len(all_addr), 2) @asynctest.fail_on(active_handles=True) async def test_post_put_delete_address(self) -> None: nicknames = list(self.address_data.keys()) self.assertGreaterEqual(len(nicknames), 2) addr0 = self.address_data[nicknames[0]] key = await self.service.post_address(addr0) val = await self.service.get_address(key) self.assertEqual(addr0, val) addr1 = self.address_data[nicknames[1]] await self.service.put_address(key, addr1) val = await self.service.get_address(key) self.assertEqual(addr1, val) await self.service.delete_address(key) with self.assertRaises(KeyError): await self.service.get_address(key)
def run_server( app: tornado.web.Application, service: AddressBookService, config: Dict, port: int, logger: logging.Logger, debug: bool, ): name = config['service']['name'] # Install async IO event loop instead of Tornado's IO loop for standard # async/await code and Tornado to work in same even loop. tasyncio.AsyncIOMainLoop().install() # Register loop.stop() as signal handler # In 3.6, shutting down gracefully is a lot simpler: # # try: # loop.run_forever() # finally: # loop.run_until_complete(loop.shutdown_asyncgens()) # loop.close() loop = asyncio.get_event_loop() for sig in (signal.SIGINT, signal.SIGTERM): loop.add_signal_handler(sig, loop.stop) # Start auth, caller's start_up and server service.start() # Start http server http_server_args = {'decompress_request': True} http_server = app.listen(port, '', **http_server_args) msg = 'Starting {} on port {} ...'.format(name, port) logger.info(msg) # Start event loop # asyncio equivalent of tornado.ioloop.IOLoop.current().start() loop.run_forever() # Begin shutdown after loop.stop() upon receiving signal msg = 'Shutting down {}...'.format(name) logger.info(msg) http_server.stop() # Run unfinished tasks and stop event loop loop.run_until_complete(asyncio.gather(*asyncio.Task.all_tasks())) service.stop() loop.close() # Service stopped msg = 'Stopped {}.'.format(name) logger.info(msg)
class AddressBookServiceWithInMemoryDBTest(asynctest.TestCase): async def setUp(self) -> None: logging.config.dictConfig(TEST_CONFIG['logging']) logger = logging.getLogger(LOGGER_NAME) self.service = AddressBookService(config=TEST_CONFIG, logger=logger) self.service.start() self.address_data = address_data_suite() for nickname, val in self.address_data.items(): addr = AddressEntry.from_api_dm(val) await self.service.addr_db.create_address(addr, nickname) async def tearDown(self) -> None: self.service.stop() @asynctest.fail_on(active_handles=True) async def test_get_address(self) -> None: for nickname, addr in self.address_data.items(): value = await self.service.get_address(nickname) self.assertEqual(addr, value) @asynctest.fail_on(active_handles=True) async def test_get_all_addresses(self) -> None: all_addr = {} async for nickname, addr in self.service.get_all_addresses(): all_addr[nickname] = addr self.assertEqual(len(all_addr), 2) @asynctest.fail_on(active_handles=True) async def test_crud_address(self) -> None: nicknames = list(self.address_data.keys()) self.assertGreaterEqual(len(nicknames), 2) addr0 = self.address_data[nicknames[0]] key = await self.service.create_address(addr0) val = await self.service.get_address(key) self.assertEqual(addr0, val) addr1 = self.address_data[nicknames[1]] await self.service.update_address(key, addr1) val = await self.service.get_address(key) self.assertEqual(addr1, val) await self.service.delete_address(key) with self.assertRaises(KeyError): await self.service.get_address(key)
def make_addrservice_app( config: Dict, debug: bool, logger: logging.Logger = logging.getLogger(LOGGER_NAME) ) -> Tuple[AddressBookService, tornado.web.Application]: service = AddressBookService.from_config(config) app = tornado.web.Application( [ # Heartbeat (r'/healthz/?', LivenessRequestHandler, dict(service=service, config=config, logger=logger)), # noqa (r'/readiness/?', ReadinessRequestHandler, dict(service=service, config=config, logger=logger)), # noqa # Address Book endpoints (ADDRESSBOOK_REGEX, AddressBookRequestHandler, dict(service=service, config=config, logger=logger)), # noqa (ADDRESSBOOK_ENTRY_REGEX, AddressBookEntryRequestHandler, dict(service=service, config=config, logger=logger)) # noqa ], compress_response=True, # compress textual responses log_function=log_function, # log_request() uses it to log results serve_traceback=debug, # it is passed on as setting to write_error() # TODO: Exercise: add here suitable values for default_handler_class # and default_handler_args parameters to hook in DefaultRequestHandler ) return service, app
def run_server(app: tornado.web.Application, service: AddressBookService, config: Dict, port: int, debug: bool, logger: logging.Logger): name = config['service']['name'] loop = asyncio.get_event_loop() loop.set_task_factory(context.task_factory) # Start AddressBook service service.start() # Bind http server to port http_server_args = {'decompress_request': True} http_server = app.listen(port, '', **http_server_args) logutils.log(logger, logging.INFO, message='STARTING', service_name=name, port=port) try: # Start asyncio IO event loop loop.run_forever() except KeyboardInterrupt: # signal.SIGINT pass finally: loop.stop() logutils.log(logger, logging.INFO, message='SHUTTING DOWN', service_name=name) http_server.stop() # loop.run_until_complete(asyncio.gather(*asyncio.Task.all_tasks())) loop.run_until_complete(loop.shutdown_asyncgens()) service.stop() loop.close() logutils.log(logger, logging.INFO, message='STOPPED', service_name=name)
def main(args=parse_args()): ''' Starts the Tornado server serving Address Book on the given port ''' config = yaml.load(args.config.read(), Loader=yaml.SafeLoader) # First thing: set logging config logging.config.dictConfig(config['logging']) logger = logging.getLogger(LOGGER_NAME) addr_db = create_addressbook_db(config['addr-db']) addr_service = AddressBookService(addr_db) addr_app = make_addrservice_app(addr_service, config, args.debug) run_server( app=addr_app, service=addr_service, config=config, port=args.port, logger=logger, debug=args.debug, )