Exemplo n.º 1
0
async def test_subscription(
    client, headers, subscription_query, mutation_city, city_name
):
    request = GraphQLRequest(query=subscription_query, headers=headers)
    m = []

    def callback(data):
        assert "city" in data
        m.append(data)
        if len(m) > 1:
            city = data.get("city")[0]
            assert city.get("name") == city_name
            subscription.unsubscribe()

    callbacks = CallbackRegistry()
    callbacks.register(
        GraphQLSubscriptionEventType.DATA, lambda event: callback(event.payload.data)
    )

    subscription: GraphQLSubscription = await client.subscribe(
        request=request, callbacks=callbacks, headers=headers,
    )

    await asyncio.sleep(0.1)

    request = GraphQLRequest(query=mutation_city, headers=headers)
    _ = await client.query(request)

    try:
        await asyncio.wait_for(subscription.task, timeout=1)
        assert len(m) == 2
    except asyncio.TimeoutError:
        pytest.fail("Subscriptions timed out before receiving expected messages")
Exemplo n.º 2
0
def test_callback_registry_coro_without_loop(caplog):
    async def hello():
        pass

    registry = CallbackRegistry(callbacks={"hello": hello})

    with pytest.warns(RuntimeWarning):
        registry.dispatch("hello")
        assert "Callback triggered without a running loop" in caplog.text
        assert f"skipping {str(hello)}" in caplog.text
Exemplo n.º 3
0
def test_callback_registry_multiple(mocker):
    callback_one = mocker.Mock()
    callback_two = mocker.Mock()
    registry = CallbackRegistry(
        callbacks={"event": [callback_one, callback_two]})

    assert len(registry.callbacks("event")) == 2

    registry.dispatch("event", "event")

    callback_one.assert_called_once()
    callback_one.assert_called_once_with("event")

    callback_two.assert_called_once()
    callback_two.assert_called_once_with("event")

    callback_one.reset_mock()
    callback_two.reset_mock()

    registry.deregister("event", callback_two)
    registry.dispatch("event", "event")

    callback_one.assert_called_once()
    callback_one.assert_called_once_with("event")

    callback_two.assert_not_called()
Exemplo n.º 4
0
    def __post_init__(
        self,
        headers: Optional[Dict[str, str]] = None,
        operation: Optional[str] = None,
        variables: Optional[Dict[str, Any]] = None,
    ):
        super().__post_init__(headers, operation, variables)

        if self.callbacks is None:
            object.__setattr__(self, "callbacks", CallbackRegistry())
        elif isinstance(self.callbacks, dict):
            object.__setattr__(self, "callbacks",
                               CallbackRegistry(callbacks=self.callbacks))
Exemplo n.º 5
0
def test_callback_registry_exists(mocker):
    callback = mocker.Mock()

    registry = CallbackRegistry()
    registry.register("one", callback)

    assert registry.exists("one", callback)
    assert registry.exists("one", Callback(callback))
    assert not registry.exists(None, callback)
    assert not registry.exists("two", callback)
Exemplo n.º 6
0
def test_callback_registry_callbacks(mocker):
    callback_one = mocker.Mock()
    callback_two = mocker.Mock()
    callback_default = mocker.Mock()

    registry = CallbackRegistry()
    registry.register("one", callback_one)
    registry.register("two", callback_two)
    registry.register(None, callback_default)

    assert registry.callbacks() == [Callback(callback_default)]
    assert registry.callbacks("one") == [Callback(callback_one)]
    assert registry.callbacks("two") == [Callback(callback_two)]
Exemplo n.º 7
0
def test_callback_registry_simple(mocker):
    callback_one = mocker.Mock()
    callback_two = mocker.Mock()
    registry = CallbackRegistry(callbacks={
        "one": callback_one,
        "two": callback_two
    })
    registry.dispatch("one", "one")
    registry.dispatch("two", "two")
    registry.dispatch(None, "None")

    callback_one.assert_called_once()
    callback_one.assert_called_once_with("one")

    callback_two.assert_called_once()
    callback_two.assert_called_once_with("two")

    callback_one.reset_mock()
    registry.deregister("one", callback_one)
    registry.dispatch("one", "one")

    callback_one.assert_not_called()
Exemplo n.º 8
0
def test_callback_registry_callbacks_default(mocker):
    callback = mocker.Mock()
    registry = CallbackRegistry()

    assert registry.callbacks() == []

    registry.register(None, callback)
    assert registry.callbacks() == [Callback(callback)]
Exemplo n.º 9
0
 async def subscribe(
     self,
     request: GraphQLRequest,
     callbacks: Optional[CallbackRegistry] = None,
     headers: Optional[Dict[str, str]] = None,
 ) -> GraphQLSubscription:
     await self._validate(request, headers=headers)
     headers = headers or {}
     subscription = GraphQLSubscription(
         request=request,
         callbacks=callbacks or CallbackRegistry(),
         headers={**self._headers, **request.headers, **headers},
     )
     subscription.task = asyncio.create_task(self._subscribe(subscription))
     return subscription
Exemplo n.º 10
0
    async def subscribe(
        self,
        request: GraphQLRequest,
        headers: Optional[Dict[str, str]] = None,
        operation: Optional[str] = None,
        variables: Optional[Dict[str, Any]] = None,
        callbacks: Optional[CallbacksType] = None,
        on_data: Optional[CallbackType] = None,
        on_error: Optional[CallbackType] = None,
        session: Optional[aiohttp.ClientSession] = None,
        wait: bool = False,
    ) -> GraphQLSubscription:
        """
        Create and initialise a GraphQL subscription. Once subscribed and a known event
        is received, all registered callbacks for the event type is triggered with the
        :class:`aiographql.client.GraphQLSubscriptionEvent` instance passed in the first
        argument.

        The following example will start a subscription that prints all data events as
        it receives them.

        .. code-block:: python

            # initialise and subscribe to events in the background
            subscription: GraphQLSubscription = await client.subscribe(
                request="{ notifications: { id, summary } }",
                on_data=lambda event: print(f"Data: {event}"),
                on_error=lambda event: print(f"Error: {event}"),
            )
            # process events for 10 seconds then unsubscribe
            await asyncio.wait(subscription.task, timeout=10)
            subscription.unsubscribe()

        :param request: Request to send to the GraphQL server.
        :param headers: Additional headers to be set when sending HTTP request.
        :param operation: GraphQL operation name to use if the `GraphQLRequest.query`
                          contains named operations. This will override any default
                          operation set.
        :param variables: Query variables to set for the provided request. This will
                          override the default values for any existing variables in the
                          request if set.
        :param session: Optional `aiohttp.ClientSession` to use for requests
        :return: The resulting `GraphQLResponse` object.
        :param callbacks: Custom callback registry mapping an event to one more more
            callback methods. If not provided, a new instance is created.
        :param on_data: Callback to use when data event is received.
        :param on_error: Callback to use when an error occurs.
        :param session: Optional session to use for connecting the graphql endpoint, if
            one is not provided, a new session is created for the duration of the
            subscription.
        :param wait: If set to `True`, this method will wait until the subscription
            is completed, websocket disconnected or async task cancelled.
        :return: The initialised subscription.
        """
        request = self._prepare_request(request=request,
                                        operation=operation,
                                        variables=variables,
                                        headers=headers)
        await self.validate(request=request)

        callbacks = callbacks or CallbackRegistry()
        if on_data:
            callbacks.register(GraphQLSubscriptionEventType.DATA, on_data)
        if on_error:
            callbacks.register(GraphQLSubscriptionEventType.ERROR, on_error)

        subscription = GraphQLSubscription(request=request,
                                           callbacks=callbacks)
        await subscription.subscribe(endpoint=self.endpoint,
                                     session=session or self._session,
                                     wait=wait)
        return subscription
Exemplo n.º 11
0
def test_callback_registry_deregister_non_existing():
    # noinspection PyBroadException
    try:
        CallbackRegistry().deregister("one", lambda x: None)
    except Exception:
        pytest.fail("Unexpected exception")
Exemplo n.º 12
0
def test_callback_registry_default(mocker):
    callback = mocker.Mock()
    registry = CallbackRegistry()
    registry.register(None, callback)

    registry.dispatch("doesnotexist", "one")

    callback.assert_called_once()
    callback.assert_called_once_with("one")

    callback.reset_mock()
    registry.dispatch(None, "one")

    callback.assert_called_once()
    callback.assert_called_once_with("one")

    callback.reset_mock()
    registry.deregister(None, callback)
    registry.dispatch("doesnotexist", "two")
    registry.dispatch(None, "two")

    callback.assert_not_called()