import asyncio from unittest.mock import AsyncMock import pytest from gql import gql as gql_query from gql.transport.exceptions import TransportAlreadyConnected from pytest_mock import MockerFixture from delivery_metadata import config from delivery_metadata.connectors.graphql import GraphQlConnector, TransportTimeoutError TOKEN = "test-m2m-token" def make_connector(mocker: MockerFixture) -> GraphQlConnector: connector = GraphQlConnector.__new__(GraphQlConnector) token_manager: AsyncMock = mocker.AsyncMock() token_manager.get_token_string.return_value = TOKEN connector._token_manager = token_manager return connector @pytest.mark.asyncio async def test_make_request(mocker: MockerFixture) -> None: mock_transport = mocker.patch( "delivery_metadata.connectors.graphql.AIOHTTPTransport" ) mock_transport.return_value.close = mocker.AsyncMock() mock_client = mocker.patch("delivery_metadata.connectors.graphql.Client") mock_client.return_value.execute_async = mocker.AsyncMock() connector = make_connector(mocker) query = """ query doSomething { func { data { id } } } """ params = {"abc": "123"} result = await connector.make_request(query, params) mock_transport.assert_called_once_with( url="https://test-graphql-router.theorchard.io/graphql", headers={ "apollographql-client-name": config.SERVICE_NAME, "apollographql-client-version": config.SERVICE_VERSION, "Content-Type": "application/json", "Authorization": f"Bearer {TOKEN}", "Orchard-User-Id": "oa:179", }, ssl=True, ) mock_client.return_value.execute_async.assert_awaited_once_with( gql_query(query), variable_values=params ) mock_client.assert_called_once_with(transport=mock_transport.return_value) assert result == mock_client.return_value.execute_async.return_value mock_transport.return_value.close.assert_awaited_once() @pytest.mark.asyncio async def test_timeout(mocker: MockerFixture) -> None: mock_transport = mocker.patch( "delivery_metadata.connectors.graphql.AIOHTTPTransport" ) mock_transport.return_value.close = mocker.AsyncMock() mock_client = mocker.patch("delivery_metadata.connectors.graphql.Client") mock_client.return_value.execute_async = mocker.AsyncMock(side_effect=TimeoutError) connector = make_connector(mocker) query = """ query doSomething { func { data { id } } } """ with pytest.raises(TransportTimeoutError): await connector.make_request(query, {"abc": "123"}) mock_transport.return_value.close.assert_awaited_once() @pytest.mark.asyncio async def test_make_request_concurrent_requests_use_separate_transports( mocker: MockerFixture, ) -> None: mock_client = mocker.patch("delivery_metadata.connectors.graphql.Client") mock_client.return_value.execute_async = mocker.AsyncMock() mocker.patch( "delivery_metadata.connectors.graphql.AIOHTTPTransport", side_effect=lambda **_: mocker.MagicMock(close=mocker.AsyncMock()), ) connector = make_connector(mocker) query = """ query doSomething { func { data { id } } } """ await asyncio.gather( connector.make_request(query), connector.make_request(query), ) client_1, client_2 = mock_client.call_args_list assert client_1.kwargs["transport"] != client_2.kwargs["transport"] @pytest.mark.asyncio async def test_using_same_transport_concurrently_gives_transport_already_connected_error( mocker: MockerFixture, ) -> None: query = """ query doSomething { func { data { id } } } """ query_document_node = gql_query(query) connector = make_connector(mocker) with pytest.raises(TransportAlreadyConnected): async with connector._create_session() as session: await asyncio.gather( session.execute_async(query_document_node), session.execute_async(query_document_node), )