예제 #1
0
    async def accepts_type_definition_with_async_subscribe_function():
        pubsub = EventEmitter()

        async def subscribe_email(_inbox, _info):
            return EventEmitterAsyncIterator(pubsub, "importantEmail")

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

        ast = parse("""
            subscription {
              importantEmail
            }
            """)

        subscription = await subscribe(schema, ast)

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

        await anext(subscription)
예제 #2
0
 async def aclose_cleans_up():
     emitter = EventEmitter()
     assert emitter.listeners["publish"] == []
     iterator = EventEmitterAsyncIterator(emitter, "publish")
     assert emitter.listeners["publish"] == [iterator.queue.put]
     assert not iterator.closed
     for value in range(3):
         emitter.emit("publish", value)
     await sleep(0)
     assert iterator.queue.qsize() == 3
     await iterator.aclose()
     assert emitter.listeners["publish"] == []
     assert iterator.queue.empty()
     assert iterator.closed
예제 #3
0
    async def produces_a_payload_for_multiple_subscribe_in_same_subscription():
        pubsub = EventEmitter()
        send_important_email, subscription = await create_subscription(pubsub)
        second = await create_subscription(pubsub)

        payload1 = anext(subscription)
        payload2 = anext(second[1])

        assert (send_important_email({
            "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)
예제 #4
0
    async def accepts_multiple_subscription_fields_defined_in_schema():
        pubsub = EventEmitter()
        SubscriptionTypeMultiple = GraphQLObjectType(
            "Subscription",
            {
                "importantEmail": GraphQLField(EmailEventType),
                "nonImportantEmail": GraphQLField(EmailEventType),
            },
        )

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

        send_important_email, subscription = await create_subscription(
            pubsub, test_schema
        )

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

        await anext(subscription)
예제 #5
0
    async def produces_a_payload_for_multiple_subscribe_in_same_subscription():
        pubsub = EventEmitter()
        send_important_email, subscription = await create_subscription(pubsub)
        second = await create_subscription(pubsub)

        payload1 = anext(subscription)
        payload2 = anext(second[1])

        assert send_important_email({
            '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)
예제 #6
0
    async def event_order_is_correct_for_multiple_publishes():
        pubsub = EventEmitter()
        send_important_email, subscription = await create_subscription(pubsub)

        payload = anext(subscription)

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

        # A new email arrives!
        assert (send_important_email({
            "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 = subscription.__anext__()

        assert await payload == (
            {
                "importantEmail": {
                    "email": {
                        "from": "*****@*****.**",
                        "subject": "Message 2"
                    },
                    "inbox": {
                        "unread": 2,
                        "total": 3
                    },
                }
            },
            None,
        )
예제 #7
0
    async def produces_a_payload_when_there_are_multiple_events():
        pubsub = EventEmitter()
        send_important_email, subscription = await create_subscription(pubsub)
        payload = anext(subscription)

        # A new email arrives!
        assert (send_important_email({
            "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 (send_important_email({
            "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,
        )
예제 #8
0
    async def resolves_to_an_error_if_variables_were_wrong_type():
        # If we receive variables that cannot be coerced correctly, subscribe()
        # will resolve to an ExecutionResult that contains an informative error
        # description.
        ast = parse(
            """
            subscription ($priority: Int) {
              importantEmail(priority: $priority) {
                email {
                  from
                  subject
                }
                inbox {
                  unread
                  total
                }
              }
            }
            """
        )

        pubsub = EventEmitter()
        data = {
            "inbox": {
                "emails": [
                    {
                        "from": "*****@*****.**",
                        "subject": "Hello",
                        "message": "Hello World",
                        "unread": False,
                    }
                ]
            },
            "importantEmail": lambda _info: EventEmitterAsyncIterator(
                pubsub, "importantEmail"
            ),
        }

        result = await subscribe(
            email_schema, ast, data, variable_values={"priority": "meow"}
        )

        assert result == (
            None,
            [
                {
                    "message": "Variable '$priority' got invalid value 'meow'; Expected"
                    " type Int; Int cannot represent non-integer value: 'meow'",
                    "locations": [(2, 27)],
                }
            ],
        )

        assert result.errors[0].original_error is not None
예제 #9
0
    async def should_not_trigger_when_subscription_is_thrown():
        pubsub = EventEmitter()
        send_important_email, subscription = await create_subscription(pubsub)
        payload = anext(subscription)

        # A new email arrives!
        assert (
            send_important_email(
                {
                    "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 (
            send_important_email(
                {
                    "from": "*****@*****.**",
                    "subject": "Alright 2",
                    "message": "Tests are good 2",
                    "unread": True,
                }
            )
            is False
        )

        with raises(StopAsyncIteration):
            await payload
예제 #10
0
    async def event_order_is_correct_for_multiple_publishes():
        pubsub = EventEmitter()
        send_important_email, subscription = await create_subscription(pubsub)

        payload = anext(subscription)

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

        # A new email arrives!
        assert send_important_email({
            '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 = subscription.__anext__()

        assert await payload == ({
            'importantEmail': {
                'email': {
                    'from': '*****@*****.**',
                    'subject': 'Message 2'
                },
                'inbox': {
                    'unread': 2,
                    'total': 3
                },
            }
        }, None)
예제 #11
0
    async def resolves_to_an_error_for_unknown_subscription_field():
        ast = parse("""
            subscription {
              unknownField
            }
            """)

        pubsub = EventEmitter()

        subscription = (await create_subscription(pubsub, ast=ast))[1]

        assert subscription == (None, [{
            'message': "The subscription field 'unknownField' is not defined.",
            'locations': [(3, 15)]
        }])
예제 #12
0
    async def should_not_trigger_when_subscription_is_already_done():
        pubsub = EventEmitter()
        send_important_email, subscription = await create_subscription(pubsub)
        payload = anext(subscription)

        # A new email arrives!
        assert (
            send_important_email(
                {
                    "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 (
            send_important_email(
                {
                    "from": "*****@*****.**",
                    "subject": "Alright 2",
                    "message": "Tests are good 2",
                    "unread": True,
                }
            )
            is False
        )

        with raises(StopAsyncIteration):
            await payload
예제 #13
0
    async def resolves_to_an_error_if_variables_were_wrong_type():
        # If we receive variables that cannot be coerced correctly, subscribe()
        # will resolve to an ExecutionResult that contains an informative error
        # description.
        ast = parse("""
            subscription ($priority: Int) {
              importantEmail(priority: $priority) {
                email {
                  from
                  subject
                }
                inbox {
                  unread
                  total
                }
              }
            }
            """)

        pubsub = EventEmitter()
        data = {
            'inbox': {
                'emails': [{
                    'from': '*****@*****.**',
                    'subject': 'Hello',
                    'message': 'Hello World',
                    'unread': False
                }]
            },
            'importantEmail':
            lambda _info: EventEmitterAsyncIterator(pubsub, 'importantEmail')
        }

        result = await subscribe(email_schema,
                                 ast,
                                 data,
                                 variable_values={'priority': 'meow'})

        assert result == (None, [{
            'message':
            "Variable '$priority' got invalid value 'meow'; Expected"
            " type Int; Int cannot represent non-integer value: 'meow'",
            'locations': [(2, 27)]
        }])

        assert result.errors[0].original_error is not None
예제 #14
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 = EventEmitter()

        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'")
예제 #15
0
async def startup(app):
    authentication = AuthenticationMiddleware(
        whitelist=['__schema', 'registerUser', 'authenticate'])

    db = app['mongo']
    config = app['config']
    event_emitter = EventEmitter()

    repositories = edict(admin=AdminRepository(),
                         user=UserRepository(),
                         blog=BlogRepository(),
                         post=PostRepository(),
                         comment=CommentRepository())

    data_loader_registry = DbDataLoaderRegistry()
    for repository in repositories.values():
        repository.register_data_loaders(data_loader_registry)

    context_builder = lambda request: edict(config=config,
                                            db=db,
                                            event_emitter=event_emitter,
                                            repositories=repositories,
                                            data_loaders=data_loader_registry.
                                            create_loders(db),
                                            request=request)

    middleware = [authentication]

    controller = GraphQLController(schema, context_builder, middleware)
    routes = controller.add_routes(app)

    app['graphql'] = controller

    # Configure default CORS settings.
    cors = aiohttp_cors.setup(app,
                              defaults={
                                  "*":
                                  aiohttp_cors.ResourceOptions(
                                      allow_credentials=True,
                                      expose_headers="*",
                                      allow_headers="*",
                                  )
                              })

    for route in routes:
        cors.add(route)
예제 #16
0
    async def emit_async():
        emitter = EventEmitter()
        emitted = []

        async def listener(value):
            emitted.append(value)

        emitter.add_listener("foo", listener)
        emitter.emit("foo", "bar")
        emitter.emit("bar", "baz")
        await sleep(0)
        assert emitted == ["bar"]
예제 #17
0
    async def emit_async():
        emitter = EventEmitter()
        emitted = []

        async def listener(value):
            emitted.append(value)

        emitter.add_listener('foo', listener)
        emitter.emit('foo', 'bar')
        emitter.emit('bar', 'baz')
        await sleep(0)
        assert emitted == ['bar']
예제 #18
0
    def emit_sync():
        emitter = EventEmitter()
        emitted = []

        def listener(value):
            emitted.append(value)

        emitter.add_listener("foo", listener)
        assert emitter.emit("foo", "bar") is True
        assert emitted == ["bar"]
        assert emitter.emit("bar", "baz") is False
        assert emitted == ["bar"]
예제 #19
0
    def emit_sync():
        emitter = EventEmitter()
        emitted = []

        def listener(value):
            emitted.append(value)

        emitter.add_listener('foo', listener)
        assert emitter.emit('foo', 'bar') is True
        assert emitted == ['bar']
        assert emitter.emit('bar', 'baz') is False
        assert emitted == ['bar']
예제 #20
0
    async def subscribe_async_iterator_mock():
        # Create an AsyncIterator from an EventEmitter
        emitter = EventEmitter()
        iterator = EventEmitterAsyncIterator(emitter, "publish")

        # Make sure it works as an async iterator
        assert iterator.__aiter__() is iterator
        assert callable(iterator.__anext__)

        # Queue up publishes
        assert emitter.emit("publish", "Apple") is True
        assert emitter.emit("publish", "Banana") is True

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

        # Read ahead
        i3 = iterator.__anext__()
        i4 = iterator.__anext__()

        # Publish
        assert emitter.emit("publish", "Coconut") is True
        assert emitter.emit("publish", "Durian") is True

        # Await results
        assert await i3 == "Coconut"
        assert await i4 == "Durian"

        # Read ahead
        i5 = iterator.__anext__()

        # Terminate emitter
        await iterator.aclose()

        # Publish is not caught after terminate
        assert emitter.emit("publish", "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__()
예제 #21
0
    async def accepts_multiple_subscription_fields_defined_in_schema():
        pubsub = EventEmitter()
        SubscriptionTypeMultiple = GraphQLObjectType(
            'Subscription', {
                'importantEmail': GraphQLField(EmailEventType),
                'nonImportantEmail': GraphQLField(EmailEventType)
            })

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

        send_important_email, subscription = await create_subscription(
            pubsub, test_schema)

        send_important_email({
            'from': '*****@*****.**',
            'subject': 'Alright',
            'message': 'Tests are good',
            'unread': True
        })

        await anext(subscription)
예제 #22
0
    async def subscribe_async_iterator_mock():
        # Create an AsyncIterator from an EventEmitter
        emitter = EventEmitter()
        iterator = EventEmitterAsyncIterator(emitter, 'publish')

        # Queue up publishes
        assert emitter.emit('publish', 'Apple') is True
        assert emitter.emit('publish', 'Banana') is True

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

        # Read ahead
        i3 = iterator.__anext__()
        i4 = iterator.__anext__()

        # Publish
        assert emitter.emit('publish', 'Coconut') is True
        assert emitter.emit('publish', 'Durian') is True

        # Await results
        assert await i3 == 'Coconut'
        assert await i4 == 'Durian'

        # Read ahead
        i5 = iterator.__anext__()

        # Terminate emitter
        await iterator.aclose()

        # Publish is not caught after terminate
        assert emitter.emit('publish', '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__()
예제 #23
0
    def add_and_remove_listeners():
        emitter = EventEmitter()

        def listener1(value):
            pass

        def listener2(value):
            pass

        emitter.add_listener("foo", listener1)
        emitter.add_listener("foo", listener2)
        emitter.add_listener("bar", listener1)
        assert emitter.listeners["foo"] == [listener1, listener2]
        assert emitter.listeners["bar"] == [listener1]
        emitter.remove_listener("foo", listener1)
        assert emitter.listeners["foo"] == [listener2]
        assert emitter.listeners["bar"] == [listener1]
        emitter.remove_listener("foo", listener2)
        assert emitter.listeners["foo"] == []
        assert emitter.listeners["bar"] == [listener1]
        emitter.remove_listener("bar", listener1)
        assert emitter.listeners["bar"] == []
예제 #24
0
 def emitter(self) -> EventEmitter:
     if not self._emitter:
         self._emitter = self._emitter = EventEmitter(self._loop)
     return self._emitter
예제 #25
0
    async def produces_a_payload_per_subscription_event():
        pubsub = EventEmitter()
        send_important_email, subscription = await create_subscription(pubsub)

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

        # A new email arrives!
        assert (send_important_email({
            "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 subscription.___anext__ is called.
        assert (send_important_email({
            "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 (send_important_email({
            "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)
예제 #26
0
 def subscribe_non_important(_inbox, _info):
     did_resolve["nonImportantEmail"] = True
     return EventEmitterAsyncIterator(EventEmitter(), "event")
예제 #27
0
 def __init__(self):
     self.emitter = EventEmitter()
     self.queue = EventEmitterAsyncIterator(self.emitter, "library")
예제 #28
0
    def add_and_remove_listeners():
        emitter = EventEmitter()

        def listener1(value):
            pass

        def listener2(value):
            pass

        emitter.add_listener('foo', listener1)
        emitter.add_listener('foo', listener2)
        emitter.add_listener('bar', listener1)
        assert emitter.listeners['foo'] == [listener1, listener2]
        assert emitter.listeners['bar'] == [listener1]
        emitter.remove_listener('foo', listener1)
        assert emitter.listeners['foo'] == [listener2]
        assert emitter.listeners['bar'] == [listener1]
        emitter.remove_listener('foo', listener2)
        assert emitter.listeners['foo'] == []
        assert emitter.listeners['bar'] == [listener1]
        emitter.remove_listener('bar', listener1)
        assert emitter.listeners['bar'] == []
예제 #29
0
 def __init__(self, **users):
     self._registry: Dict[str, User] = users
     self._emitter = EventEmitter()
예제 #30
0
    notes: [Note!]!
    notesContaining(query: String!): [Note!]!
}

type Mutation {
    createNote(title: String!, body: String!): Note!
    sendMessage(message: String!): Boolean!
}

type Subscription {
    messages: String!
}
"""
)
mutation = ResolverMap("Mutation")
pubsub = EventEmitter()
query = ResolverMap("Query")
subscription = SubscriptionAwareResolverMap("Subscription")


@query.field("hello")
async def say_hello(root, info):
    await asyncio.sleep(3)
    return "Hello!"


@query.field("notes")
async def get_all_notes(root, info):
    await init_database()  # FIXME: channels needs to expose the ready_callable from daphne
    notes = await Note.query.gino.all()
    return notes