async def test_instantiate_one_consumer_per_handler_one_handler_registered( self): """ Para cada handler registrado, teremos um Consumer. Esse Consumer conseguirá consumir múltiplas filas, se necessário. """ app = App(**self.connection_parameters) @app.route(["asgard/counts"], vhost="/") async def _handler(message): return message consumers = app._build_consumers() self.assertEqual(1, len(consumers)) self.assertEqual(["asgard/counts"], consumers[0].queue_name) self.assertEqual("/", consumers[0].vhost) queue_connection_parameters = consumers[0].queue.connection_parameters self.assertEqual(self.connection_parameters['host'], queue_connection_parameters['host']) self.assertEqual(self.connection_parameters['user'], queue_connection_parameters['login']) self.assertEqual(self.connection_parameters['password'], queue_connection_parameters['password']) self.assertEqual(self.connection_parameters['prefetch_count'], consumers[0].queue.prefetch_count)
async def test_instantiate_one_consumer_per_handler_multiple_handlers_registered(self): app = App(**self.connection_parameters) @app.route(["asgard/counts"], vhost="/") async def _handler(message): return message @app.route(["asgard/counts/errors"], vhost="fluentd") async def _other_handler(message): return message consumers = app._build_consumers() self.assertEqual(2, len(consumers)) self.assertEqual(["asgard/counts"], consumers[0].queue_name) self.assertEqual("/", consumers[0].vhost) queue_connection_parameters = consumers[0].queue.connection_parameters self.assertEqual(self.connection_parameters['host'], queue_connection_parameters['host']) self.assertEqual(self.connection_parameters['user'], queue_connection_parameters['login']) self.assertEqual(self.connection_parameters['password'], queue_connection_parameters['password']) self.assertEqual(self.connection_parameters['prefetch_count'], consumers[0].queue.prefetch_count) self.assertEqual(["asgard/counts/errors"], consumers[1].queue_name) self.assertEqual("fluentd", consumers[1].vhost) queue_connection_parameters = consumers[1].queue.connection_parameters self.assertEqual(self.connection_parameters['host'], queue_connection_parameters['host']) self.assertEqual(self.connection_parameters['user'], queue_connection_parameters['login']) self.assertEqual(self.connection_parameters['password'], queue_connection_parameters['password']) self.assertEqual(self.connection_parameters['prefetch_count'], consumers[1].queue.prefetch_count)
async def test_raise_if_object_is_not_callable(self): app = App() class MyHandler: pass handler = MyHandler() with self.assertRaises(TypeError): app.route(["/"], type=RouteTypes.HTTP, methods=["GET"])(handler)
async def test_can_registrer_a_callable_as_a_valid_handler(self): app = App() class MyHandler: async def __call__(self, wrapper: RequestWrapper): return web.json_response({"OK": True}) handler = MyHandler() app.route(["/"], type=RouteTypes.HTTP, methods=["GET"])(handler) async with HttpClientContext(app) as client: resp = await client.get("/") data = await resp.json() self.assertEqual({"OK": True}, data)
async def test_check_route_registry_full_options(self): expected_route = ["/asgard/counts/ok"] expected_vhost = "/" app = App(**self.connection_parameters) @app.route(expected_route, vhost=expected_vhost, options={ Options.BULK_SIZE: 1024, Options.BULK_FLUSH_INTERVAL: 120 }) async def _handler(message): return 42 self.assertIsNotNone(app.routes_registry) expected_registry_entry = { "route": expected_route, "handler": _handler, "options": { "vhost": expected_vhost, "bulk_size": 1024, "bulk_flush_interval": 120, Events.ON_SUCCESS: Actions.ACK, Events.ON_EXCEPTION: Actions.REQUEUE, } } self.assertEqual(expected_registry_entry, app.routes_registry[_handler]) self.assertEqual(42, await app.routes_registry[_handler]['handler'] (None))
async def test_it_uses_the_connection_provided_by_the_route_if_one_exists( self): conn = AMQPConnection( hostname="127.0.0.1", username="******", password="******", prefetch=1024, ) app = App(connections=[]) @app.route( routes=["a_queue_name"], type=RouteTypes.AMQP_RABBITMQ, options={"connection": conn}, ) async def mock_handler(*args, **kwargs): pass MockedConsumer = Mock(return_value=Mock(spec=Consumer, queue=Mock())) with patch("asyncworker.signals.handlers.rabbitmq.Consumer", MockedConsumer): await self.signal_handler.startup(app) MockedConsumer.assert_called_once_with( route_info=ANY, host=conn.hostname, username=conn.username, password=conn.password, prefetch_count=conn.prefetch, )
async def test_check_route_registry_full_options(self): expected_routes = ["/asgard/counts/ok"] expected_vhost = "/" app = App(**self.connection_parameters) @app.route( expected_routes, type=RouteTypes.AMQP_RABBITMQ, vhost=expected_vhost, options={Options.BULK_SIZE: 1024, Options.BULK_FLUSH_INTERVAL: 120}, ) async def _handler(message): return 42 self.assertIsNotNone(app.routes_registry) expected_registry_entry = { "type": RouteTypes.AMQP_RABBITMQ, "routes": expected_routes, "handler": _handler, "default_options": {}, "vhost": expected_vhost, "options": { "bulk_size": 1024, "bulk_flush_interval": 120, Events.ON_SUCCESS: Actions.ACK, Events.ON_EXCEPTION: Actions.REQUEUE, }, } route = app.routes_registry.route_for(_handler) self.assertEqual(expected_registry_entry, route) self.assertEqual(42, await route["handler"](None))
def __init__( # nosec self, hostname: str = "127.0.0.1", username: str = "guest", password: str = "guest", prefetch: int = 10, connection_name: str = "default", ): self.__connection = AMQPConnection( name=connection_name, hostname=hostname, username=username, password=password, prefetch=prefetch ) self.__app = App(connections=[self.__connection])
def setUp(self): self.queue_mock = Mock(connection=Mock(is_connected=True), spec=JsonQueue) self.logger_mock = CoroutineMock(info=CoroutineMock(), debug=CoroutineMock(), error=CoroutineMock()) self.connection_parameters = ("127.0.0.1", "guest", "guest", 1024) self.one_route_fixture = { "routes": ["/asgard/counts/ok"], "handler": _handler, "vhost": "/", "options": { "bulk_size": 1, "bulk_flush_interval": 60, Events.ON_SUCCESS: Actions.ACK, Events.ON_EXCEPTION: Actions.REQUEUE, }, } self.app = App( **{ "host": "127.0.0.1", "user": "******", "password": "******", "prefetch_count": 1024, }) self.mock_message = self._make_msg() mock.patch.object(conf, "settings", mock.Mock(FLUSH_TIMEOUT=0.1)).start()
def setUp(self): self.queue_mock = Mock( connection=Mock(has_channel_ready=Mock(return_value=True)), spec=JsonQueue, ) self.logger_mock = CoroutineMock(info=CoroutineMock(), debug=CoroutineMock(), error=CoroutineMock()) self.connection_parameters = ("127.0.0.1", "guest", "guest", 1024) self.one_route_fixture = { "routes": ["/asgard/counts/ok"], "handler": _handler, "vhost": "/", "options": { "bulk_size": 1, "bulk_flush_interval": 1, Events.ON_SUCCESS: Actions.ACK, Events.ON_EXCEPTION: Actions.REQUEUE, }, } self.connection = AMQPConnection( hostname="127.0.0.1", username="******", password="******", prefetch=1024, ) self.app = App(connections=[self.connection]) self.mock_message = self._make_msg() mock.patch.object(conf, "settings", mock.Mock(FLUSH_TIMEOUT=0.1)).start()
async def test_instantiate_one_consumer_per_handler_one_handler_registered( self ): """ Para cada handler registrado, teremos um Consumer. Esse Consumer conseguirá consumir múltiplas filas, se necessário. """ app = App(connections=[self.connection]) @app.route(["asgard/counts"], type=RouteTypes.AMQP_RABBITMQ, vhost="/") async def _handler(message): return message await app.startup() consumers = app[RouteTypes.AMQP_RABBITMQ]["consumers"] self.assertEqual(1, len(consumers)) self.assertEqual(["asgard/counts"], consumers[0].queue_name) self.assertEqual("/", consumers[0].vhost) queue_connection_parameters = consumers[ 0 ].queue.connection.connection_parameters self.assertEqual( self.connection.hostname, queue_connection_parameters["host"] ) self.assertEqual( self.connection.username, queue_connection_parameters["login"] ) self.assertEqual( self.connection.password, queue_connection_parameters["password"] ) self.assertEqual( self.connection.prefetch, consumers[0].queue.prefetch_count )
async def test_check_route_registry_add_headers_per_handler(self): expected_route = ["/v2/events", "/other/path"] aditional_headers = {"X-Other-Header": "X-Other-Value"} app = App(connections=[SSEConnection(**self.connection_parameters)]) @app.route( expected_route, type=RouteTypes.SSE, headers=aditional_headers, options={ Options.BULK_SIZE: 1024, Options.BULK_FLUSH_INTERVAL: 120 }, ) async def _handler(message): return 42 routes = app.routes_registry.sse_routes self.assertIsNotNone(routes) expected_registry_entry = SSERoute( type=RouteTypes.SSE, routes=expected_route, handler=_handler, options={ "bulk_size": 1024, "bulk_flush_interval": 120, "headers": { **self.default_headers, **aditional_headers }, }, ) self.assertEqual(expected_registry_entry, routes[0]) self.assertEqual(42, await routes[0]["handler"](None))
async def test_check_route_registry_full_options(self): expected_route = ["/v2/events", "/other/path"] app = App(connections=[SSEConnection(**self.connection_parameters)]) @app.route( expected_route, type=RouteTypes.SSE, options={ Options.BULK_SIZE: 1024, Options.BULK_FLUSH_INTERVAL: 120 }, ) async def _handler(message): return 42 routes = app.routes_registry.sse_routes self.assertIsNotNone(routes) expected_registry_entry = { "type": RouteTypes.SSE, "routes": expected_route, "handler": _handler, "options": { "bulk_size": 1024, "bulk_flush_interval": 120, "headers": self.default_headers, }, } self.assertEqual(expected_registry_entry, routes[0]) self.assertEqual(42, await routes[0]["handler"](None)) self.assertEqual(self.logger, app.logger)
async def test_user_can_use_metrics_endpoint_if_default_is_renamed(self): """ Se estivermos com o endpoint de métricas habilitado mas o path foi trocado então devemos poder registrar um endpoint com o valor default do path de metricas Não é o melhor jeito de fazer o teste mas como o settings é instanciado no nível do módulo não temos muito com controlar o desencadear dos imports então por isso preciso ficar substiuindo os módulos para que o "novo" settings (após reload()) surta efeito. """ from asyncworker import routes app = App() with mock.patch.dict( os.environ, ASYNCWORKER_METRICS_ROUTE_PATH="/asyncworker-metrics"): reload(conf) with mock.patch.object(routes, "conf", conf): @app.http.get(["/metrics"]) async def _h(): return web.json_response({}) async with HttpClientContext(app) as client: resp = await client.get("/metrics") self.assertEqual(HTTPStatus.OK, resp.status)
async def test_consume_one_message_app_with_multiple_connections(self): conn = AMQPConnection(hostname="127.0.0.1", username="******", password="******", prefetch=1) conn_2 = AMQPConnection( hostname="127.0.0.1:5673", username="******", password="******", prefetch=1, ) await conn["/"].connection._connect() await conn["/"].connection.channel.queue_declare("queue") await conn["/"].put(data={"num": 42}, routing_key="queue") app = App(connections=[conn, conn_2]) @app.amqp.consume(["queue"], connection=conn) async def handler(msgs): global message_processed_multiple_connections message_processed_multiple_connections = True await app.startup() await asyncio.sleep(1) await app.shutdown() self.assertTrue(message_processed_multiple_connections)
async def test_patched_startup_has_cors_configured(self): app = App() app._on_startup.clear() app._on_startup.append(patched_startup) @app.route(["/new-path"], type=RouteTypes.HTTP, methods=["GET"]) async def handler(r): return web.json_response({}) client = ClientSession() await app.startup() resp = await client.get( f"http://{settings.HTTP_HOST}:{settings.HTTP_PORT}/new-path", headers={"Origin": "server.com"}, ) self.assertEqual(HTTPStatus.OK, resp.status) self.assertTrue( "Access-Control-Allow-Origin" in resp.headers, "Header do CORS não encontrado", ) self.assertEqual("server.com", resp.headers.get("Access-Control-Allow-Origin")) await app.shutdown()
async def setUp(self): self.queue_name = "test" self.connection = AMQPConnection(hostname="127.0.0.1", username="******", password="******", prefetch=1) self.app = App(connections=[self.connection])
async def test_register_action_on_success(self): app = App(**self.connection_parameters) @app.route(["my-queue"], options = {Events.ON_SUCCESS: Actions.REJECT}) async def _handler(message): return 42 self.assertIsNotNone(app.routes_registry) self.assertEqual(Actions.REJECT, app.routes_registry[_handler]['options'][Events.ON_SUCCESS])
async def test_startup_registers_one_connection_per_vhost_into_app_state( self, register): conn = AMQPConnection( hostname="127.0.0.1", username="******", password="******", prefetch=1024, ) app = App(connections=[conn]) app.routes_registry = self.routes_registry await self.signal_handler.startup(app) self.assertIn(conn, app.connections) register.assert_has_calls([ call(consumer.queue) for consumer in app[RouteTypes.AMQP_RABBITMQ]["consumers"] ])
async def test_startup_registers_one_connection_per_vhost_into_app_state( self, register): app = App( host="127.0.0.1", user="******", password="******", prefetch_count=1024, ) app.routes_registry = self.routes_registry await self.signal_handler.startup(app) self.assertIsInstance(app[RouteTypes.AMQP_RABBITMQ]["connection"], AMQPConnection) register.assert_has_calls([ call(consumer.queue) for consumer in app[RouteTypes.AMQP_RABBITMQ]["consumers"] ])
async def test_register_action_on_exception(self): app = App(**self.connection_parameters) @app.route(["my-queue"], options = {Events.ON_EXCEPTION: Actions.ACK}) async def _handler(message): return 42 self.assertIsNotNone(app.routes_registry) self.assertEqual(Actions.ACK, app.routes_registry[_handler]['options'][Events.ON_EXCEPTION])
async def test_app_receives_queue_connection(self): app = App(host="127.0.0.1", user="******", password="******", prefetch_count=1024) self.assertEqual("127.0.0.1", app.host) self.assertEqual("guest", app.user) self.assertEqual("guest", app.password) self.assertEqual(1024, app.prefetch_count)
async def test_test_register_default_actions(self): app = App(**self.connection_parameters) @app.route(["my-queue"]) async def _handler(message): return 42 self.assertIsNotNone(app.routes_registry) self.assertEqual(Actions.ACK, app.routes_registry[_handler]['options'][Events.ON_SUCCESS]) self.assertEqual(Actions.REQUEUE, app.routes_registry[_handler]['options'][Events.ON_EXCEPTION])
async def test_instantiate_one_consumer_per_handler_multiple_handlers_registered_bla( self ): app = App(connections=[self.connection]) @app.route(["asgard/counts"], type=RouteTypes.AMQP_RABBITMQ, vhost="/") async def _handler(message): return message @app.route( ["asgard/counts/errors"], type=RouteTypes.AMQP_RABBITMQ, vhost="fluentd", ) async def _other_handler(message): return message await app.startup() consumers = app[RouteTypes.AMQP_RABBITMQ]["consumers"] self.assertEqual(2, len(consumers)) self.assertEqual(["asgard/counts"], consumers[0].queue_name) self.assertEqual("/", consumers[0].vhost) queue_connection_parameters = consumers[ 0 ].queue.connection.connection_parameters self.assertEqual( self.connection.hostname, queue_connection_parameters["host"] ) self.assertEqual( self.connection.username, queue_connection_parameters["login"] ) self.assertEqual( self.connection.password, queue_connection_parameters["password"] ) self.assertEqual( self.connection.prefetch, consumers[0].queue.prefetch_count ) self.assertEqual(["asgard/counts/errors"], consumers[1].queue_name) self.assertEqual("fluentd", consumers[1].vhost) queue_connection_parameters = consumers[ 1 ].queue.connection.connection_parameters self.assertEqual( self.connection.hostname, queue_connection_parameters["host"] ) self.assertEqual( self.connection.username, queue_connection_parameters["login"] ) self.assertEqual( self.connection.password, queue_connection_parameters["password"] ) self.assertEqual( self.connection.prefetch, consumers[1].queue.prefetch_count )
async def test_register_bulk_flush_timeout(self): expected_bulk_flush_interval = 120 app = App(**self.connection_parameters) @app.route(["my-queue"], options={Options.BULK_FLUSH_INTERVAL: expected_bulk_flush_interval}) async def _handler(message): return 42 self.assertIsNotNone(app.routes_registry) self.assertEqual(expected_bulk_flush_interval, app.routes_registry[_handler]['options']['bulk_flush_interval']) self.assertEqual(42, await app.routes_registry[_handler]['handler'](None))
async def test_raise_if_handler_is_not_coroutine(self): app = App() with self.assertRaises(TypeError) as err: @app.route(["/"], type=RouteTypes.HTTP, methods=["GET"]) def handler(wrapper: RequestWrapper): return web.json_response({"OK": True}) self.assertTrue("handler must be a coroutine" in err.exception.args[0])
async def test_raise_if_handler_is_sync(self): app = App() with self.assertRaises(TypeError) as err: @app.amqp.consume(["/"]) def handler(): pass self.assertTrue("handler must be async" in err.exception.args[0])
async def test_raise_if_handler_is_not_coroutine_new_decorator(self): app = App() with self.assertRaises(TypeError) as err: @app.http.get(["/"]) def handler(wrapper: RequestWrapper): return web.json_response({"OK": True}) self.assertTrue("handler must be async" in err.exception.args[0])
async def test_register_default_bulk_size_and_default_bulk_flush_timeout(self): app = App(**self.connection_parameters) @app.route(["my-queue"]) async def _handler(message): return 42 self.assertIsNotNone(app.routes_registry) self.assertEqual(Defaultvalues.BULK_SIZE, app.routes_registry[_handler]['options']['bulk_size']) self.assertEqual(Defaultvalues.BULK_FLUSH_INTERVAL, app.routes_registry[_handler]['options']['bulk_flush_interval']) self.assertEqual(42, await app.routes_registry[_handler]['handler'](None))
async def test_raise_if_object_is_not_callable_new_decorator(self): app = App() class MyHandler: pass handler = MyHandler() with self.assertRaises(TypeError): app.http.get(["/"])(handler)