Esempio n. 1
0
    async def accepts_type_definition_with_async_subscribe_function():
        pubsub = SimplePubSub()

        async def get_subscriber(*_args):
            await asyncio.sleep(0)
            return pubsub.get_subscriber()

        schema = GraphQLSchema(
            query=QueryType,
            subscription=GraphQLObjectType(
                "Subscription",
                {
                    "importantEmail": GraphQLField(
                        GraphQLString, subscribe=get_subscriber
                    )
                },
            ),
        )

        subscription = await subscribe(
            schema,
            parse(
                """
            subscription {
              importantEmail
            }
            """
            ),
        )

        pubsub.emit({"importantEmail": {}})

        await anext(subscription)
    async def produces_a_payload_for_multiple_subscribe_in_same_subscription():
        pubsub = SimplePubSub()

        subscription = await create_subscription(pubsub)
        assert isinstance(subscription, MapAsyncIterator)

        second_subscription = await create_subscription(pubsub)
        assert isinstance(subscription, MapAsyncIterator)

        payload1 = anext(subscription)
        payload2 = anext(second_subscription)

        assert (pubsub.emit({
            "from": "*****@*****.**",
            "subject": "Alright",
            "message": "Tests are good",
            "unread": True,
        }) is True)

        expected_payload = {
            "importantEmail": {
                "email": {
                    "from": "*****@*****.**",
                    "subject": "Alright"
                },
                "inbox": {
                    "unread": 1,
                    "total": 2
                },
            }
        }

        assert await payload1 == (expected_payload, None)
        assert await payload2 == (expected_payload, None)
Esempio n. 3
0
    async def accepts_multiple_subscription_fields_defined_in_schema():
        pubsub = SimplePubSub()
        subscription_type_multiple = GraphQLObjectType(
            "Subscription",
            {
                "importantEmail": GraphQLField(EmailEventType),
                "nonImportantEmail": GraphQLField(EmailEventType),
            },
        )

        test_schema = GraphQLSchema(
            query=QueryType, subscription=subscription_type_multiple
        )

        subscription = await create_subscription(pubsub, test_schema)

        assert isinstance(subscription, MapAsyncIterator)

        pubsub.emit(
            {
                "from": "*****@*****.**",
                "subject": "Alright",
                "message": "Tests are good",
                "unread": True,
            }
        )

        await anext(subscription)
Esempio n. 4
0
 async def iterator_aclose_is_idempotent():
     pubsub = SimplePubSub()
     iterator = pubsub.get_subscriber()
     assert iterator.listening
     for n in range(3):
         await iterator.aclose()
         assert not iterator.listening
    async def produces_a_payload_when_there_are_multiple_events():
        pubsub = SimplePubSub()
        subscription = await create_subscription(pubsub)
        assert isinstance(subscription, MapAsyncIterator)

        payload = anext(subscription)

        # A new email arrives!
        assert (pubsub.emit({
            "from": "*****@*****.**",
            "subject": "Alright",
            "message": "Tests are good",
            "unread": True,
        }) is True)

        assert await payload == (
            {
                "importantEmail": {
                    "email": {
                        "from": "*****@*****.**",
                        "subject": "Alright"
                    },
                    "inbox": {
                        "unread": 1,
                        "total": 2
                    },
                }
            },
            None,
        )

        payload = anext(subscription)

        # A new email arrives!
        assert (pubsub.emit({
            "from": "*****@*****.**",
            "subject": "Alright 2",
            "message": "Tests are good 2",
            "unread": True,
        }) is True)

        assert await payload == (
            {
                "importantEmail": {
                    "email": {
                        "from": "*****@*****.**",
                        "subject": "Alright 2"
                    },
                    "inbox": {
                        "unread": 2,
                        "total": 3
                    },
                }
            },
            None,
        )
    async def event_order_is_correct_for_multiple_publishes():
        pubsub = SimplePubSub()
        subscription = await create_subscription(pubsub)
        assert isinstance(subscription, MapAsyncIterator)

        payload = anext(subscription)

        # A new email arrives!
        assert (pubsub.emit({
            "from": "*****@*****.**",
            "subject": "Message",
            "message": "Tests are good",
            "unread": True,
        }) is True)

        # A new email arrives!
        assert (pubsub.emit({
            "from": "*****@*****.**",
            "subject": "Message 2",
            "message": "Tests are good 2",
            "unread": True,
        }) is True)

        assert await payload == (
            {
                "importantEmail": {
                    "email": {
                        "from": "*****@*****.**",
                        "subject": "Message"
                    },
                    "inbox": {
                        "unread": 2,
                        "total": 3
                    },
                }
            },
            None,
        )

        payload = anext(subscription)

        assert await payload == (
            {
                "importantEmail": {
                    "email": {
                        "from": "*****@*****.**",
                        "subject": "Message 2"
                    },
                    "inbox": {
                        "unread": 2,
                        "total": 3
                    },
                }
            },
            None,
        )
Esempio n. 7
0
    async def should_not_trigger_when_subscription_is_thrown():
        pubsub = SimplePubSub()
        subscription = await create_subscription(pubsub)
        assert isinstance(subscription, MapAsyncIterator)

        payload = anext(subscription)

        # A new email arrives!
        assert (
            pubsub.emit(
                {
                    "from": "*****@*****.**",
                    "subject": "Alright",
                    "message": "Tests are good",
                    "unread": True,
                }
            )
            is True
        )

        assert await payload == (
            {
                "importantEmail": {
                    "email": {"from": "*****@*****.**", "subject": "Alright"},
                    "inbox": {"unread": 1, "total": 2},
                }
            },
            None,
        )

        payload = anext(subscription)

        # Throw error
        with raises(RuntimeError) as exc_info:
            await subscription.athrow(RuntimeError("ouch"))
        assert str(exc_info.value) == "ouch"

        # A new email arrives!
        assert (
            pubsub.emit(
                {
                    "from": "*****@*****.**",
                    "subject": "Alright 2",
                    "message": "Tests are good 2",
                    "unread": True,
                }
            )
            is False
        )

        with raises(StopAsyncIteration):
            await payload
Esempio n. 8
0
 async def iterator_aclose_empties_pull_queue():
     pubsub = SimplePubSub()
     assert not pubsub.subscribers
     iterator = pubsub.get_subscriber()
     assert len(pubsub.subscribers) == 1
     assert iterator.listening
     for _n in range(3):
         await iterator.__anext__()
     assert iterator.push_queue.qsize() == 0
     assert iterator.pull_queue.qsize() == 3
     await iterator.aclose()
     assert not pubsub.subscribers
     assert iterator.push_queue.qsize() == 0
     assert iterator.pull_queue.qsize() == 0
     assert not iterator.listening
Esempio n. 9
0
    async def should_not_trigger_when_subscription_is_already_done():
        pubsub = SimplePubSub()
        subscription = await create_subscription(pubsub)
        assert isinstance(subscription, MapAsyncIterator)

        payload = anext(subscription)

        # A new email arrives!
        assert (
            pubsub.emit(
                {
                    "from": "*****@*****.**",
                    "subject": "Alright",
                    "message": "Tests are good",
                    "unread": True,
                }
            )
            is True
        )

        assert await payload == (
            {
                "importantEmail": {
                    "email": {"from": "*****@*****.**", "subject": "Alright"},
                    "inbox": {"unread": 1, "total": 2},
                }
            },
            None,
        )

        payload = anext(subscription)
        await subscription.aclose()

        # A new email arrives!
        assert (
            pubsub.emit(
                {
                    "from": "*****@*****.**",
                    "subject": "Alright 2",
                    "message": "Tests are good 2",
                    "unread": True,
                }
            )
            is False
        )

        with raises(StopAsyncIteration):
            await payload
Esempio n. 10
0
 async def iterator_aclose_empties_push_queue():
     pubsub = SimplePubSub()
     assert not pubsub.subscribers
     iterator = pubsub.get_subscriber()
     assert len(pubsub.subscribers) == 1
     assert iterator.listening
     for value in range(3):
         pubsub.emit(value)
     await sleep(0)
     assert iterator.push_queue.qsize() == 3
     assert iterator.pull_queue.qsize() == 0
     await iterator.aclose()
     assert not pubsub.subscribers
     assert iterator.push_queue.qsize() == 0
     assert iterator.pull_queue.qsize() == 0
     assert not iterator.listening
Esempio n. 11
0
def create_subscription(
    pubsub: SimplePubSub,
    schema: GraphQLSchema = email_schema,
    document: DocumentNode = default_subscription_ast,
):
    emails: List[Email] = [
        {
            "from": "*****@*****.**",
            "subject": "Hello",
            "message": "Hello World",
            "unread": False,
        }
    ]

    def transform(new_email):
        emails.append(new_email)

        return {"importantEmail": {"email": new_email, "inbox": data["inbox"]}}

    data: Dict[str, Any] = {
        "inbox": {"emails": emails},
        "importantEmail": pubsub.get_subscriber(transform),
    }

    return subscribe(schema, document, data)
Esempio n. 12
0
    async def subscribe_async_iterator_mock():
        pubsub = SimplePubSub()
        iterator = pubsub.get_subscriber()

        # Queue up publishes
        assert pubsub.emit("Apple") is True
        assert pubsub.emit("Banana") is True

        # Read payloads
        assert await iterator.__anext__() == "Apple"
        assert await iterator.__anext__() == "Banana"

        # Read ahead
        i3 = await iterator.__anext__()
        assert isawaitable(i3)
        i4 = await iterator.__anext__()
        assert isawaitable(i4)

        # Publish
        assert pubsub.emit("Coconut") is True
        assert pubsub.emit("Durian") is True

        # Await out of order to get correct results
        assert await i4 == "Durian"
        assert await i3 == "Coconut"

        # Read ahead
        i5 = iterator.__anext__()

        # Terminate queue
        await iterator.aclose()

        # Publish is not caught after terminate
        assert pubsub.emit("Fig") is False

        # Find that cancelled read-ahead got a "done" result
        with raises(StopAsyncIteration):
            await i5

        # And next returns empty completion value
        with raises(StopAsyncIteration):
            await iterator.__anext__()
Esempio n. 13
0
    async def throws_an_error_if_subscribe_does_not_return_an_iterator():
        invalid_email_schema = GraphQLSchema(
            query=QueryType,
            subscription=GraphQLObjectType(
                "Subscription",
                {
                    "importantEmail": GraphQLField(
                        GraphQLString, subscribe=lambda _inbox, _info: "test"
                    )
                },
            ),
        )

        pubsub = SimplePubSub()

        with raises(TypeError) as exc_info:
            await create_subscription(pubsub, invalid_email_schema)

        assert str(exc_info.value) == (
            "Subscription field must return AsyncIterable. Received: 'test'."
        )
Esempio n. 14
0
    async def resolves_to_an_error_for_unknown_subscription_field():
        ast = parse(
            """
            subscription {
              unknownField
            }
            """
        )

        pubsub = SimplePubSub()

        subscription = await create_subscription(pubsub, email_schema, ast)

        assert subscription == (
            None,
            [
                {
                    "message": "The subscription field 'unknownField' is not defined.",
                    "locations": [(3, 15)],
                }
            ],
        )
def create_subscription(pubsub: SimplePubSub):
    document = parse("""
        subscription ($priority: Int = 0) {
          importantEmail(priority: $priority) {
            email {
              from
              subject
            }
            inbox {
              unread
              total
            }
          }
        }
        """)

    emails: List[Email] = [{
        "from": "*****@*****.**",
        "subject": "Hello",
        "message": "Hello World",
        "unread": False,
    }]

    def transform(new_email):
        emails.append(new_email)

        return {"importantEmail": {"email": new_email, "inbox": data["inbox"]}}

    data: Dict[str, Any] = {
        "inbox": {
            "emails": emails
        },
        "importantEmail": pubsub.get_subscriber(transform),
    }

    return subscribe(email_schema, document, data)
Esempio n. 16
0
 def subscribe_important(*_args):
     did_resolve["importantEmail"] = True
     return SimplePubSub().get_subscriber()
Esempio n. 17
0
 def subscribe_non_important(*_args):  # pragma: no cover
     did_resolve["nonImportantEmail"] = True
     return SimplePubSub().get_subscriber()
    async def produces_a_payload_per_subscription_event():
        pubsub = SimplePubSub()
        subscription = await create_subscription(pubsub)
        assert isinstance(subscription, MapAsyncIterator)

        # Wait for the next subscription payload.
        payload = anext(subscription)

        # A new email arrives!
        assert (pubsub.emit({
            "from": "*****@*****.**",
            "subject": "Alright",
            "message": "Tests are good",
            "unread": True,
        }) is True)

        # The previously waited on payload now has a value.
        assert await payload == (
            {
                "importantEmail": {
                    "email": {
                        "from": "*****@*****.**",
                        "subject": "Alright"
                    },
                    "inbox": {
                        "unread": 1,
                        "total": 2
                    },
                }
            },
            None,
        )

        # Another new email arrives, before anext(subscription) is called.
        assert (pubsub.emit({
            "from": "*****@*****.**",
            "subject": "Tools",
            "message": "I <3 making things",
            "unread": True,
        }) is True)

        # The next waited on payload will have a value.
        assert await anext(subscription) == (
            {
                "importantEmail": {
                    "email": {
                        "from": "*****@*****.**",
                        "subject": "Tools"
                    },
                    "inbox": {
                        "unread": 2,
                        "total": 3
                    },
                }
            },
            None,
        )

        # The client decides to disconnect.
        # noinspection PyUnresolvedReferences
        await subscription.aclose()

        # Which may result in disconnecting upstream services as well.
        assert (pubsub.emit({
            "from": "*****@*****.**",
            "subject": "Important",
            "message": "Read me please",
            "unread": True,
        }) is False)  # No more listeners.

        # Awaiting subscription after closing it results in completed results.
        with raises(StopAsyncIteration):
            assert await anext(subscription)