Beispiel #1
0
    async def test_pubsub_numsub(self, r: redis.Redis):
        p1 = r.pubsub()
        await p1.subscribe("foo", "bar", "baz")
        for i in range(3):
            assert (await wait_for_message(p1))["type"] == "subscribe"
        p2 = r.pubsub()
        await p2.subscribe("bar", "baz")
        for i in range(2):
            assert (await wait_for_message(p2))["type"] == "subscribe"
        p3 = r.pubsub()
        await p3.subscribe("baz")
        assert (await wait_for_message(p3))["type"] == "subscribe"

        channels = [(b"foo", 1), (b"bar", 2), (b"baz", 3)]
        assert await r.pubsub_numsub("foo", "bar", "baz") == channels
Beispiel #2
0
    async def test_late_subscribe(self, r: redis.Redis):
        def callback(message):
            messages.put_nowait(message)

        messages = asyncio.Queue()
        p = r.pubsub()
        task = asyncio.get_event_loop().create_task(p.run())
        # wait until loop gets settled.  Add a subscription
        await asyncio.sleep(0.1)
        await p.subscribe(foo=callback)
        # wait tof the subscribe to finish.  Cannot use _subscribe() because
        # p.run() is already accepting messages
        await asyncio.sleep(0.1)
        await r.publish("foo", "bar")
        message = None
        try:
            async with async_timeout.timeout(0.1):
                message = await messages.get()
        except asyncio.TimeoutError:
            pass
        task.cancel()
        # we expect a cancelled error, not the Runtime error
        # ("did you forget to call subscribe()"")
        with pytest.raises(asyncio.CancelledError):
            await task
        assert message == {
            "channel": b"foo",
            "data": b"bar",
            "pattern": None,
            "type": "message",
        }
Beispiel #3
0
 async def test_send_pubsub_ping_message(self, r: redis.Redis):
     p = r.pubsub(ignore_subscribe_messages=True)
     await p.subscribe("foo")
     await p.ping(message="hello world")
     assert await wait_for_message(p) == make_message(
         type="pong", channel=None, data="hello world", pattern=None
     )
Beispiel #4
0
 async def test_pubsub_channels(self, r: redis.Redis):
     p = r.pubsub()
     await p.subscribe("foo", "bar", "baz", "quux")
     for i in range(4):
         assert (await wait_for_message(p))["type"] == "subscribe"
     expected = [b"bar", b"baz", b"foo", b"quux"]
     assert all([channel in await r.pubsub_channels() for channel in expected])
Beispiel #5
0
 async def test_get_message_without_subscribe(self, r: redis.Redis):
     p = r.pubsub()
     with pytest.raises(RuntimeError) as info:
         await p.get_message()
     expect = ("connection not set: "
               "did you forget to call subscribe() or psubscribe()?")
     assert expect in info.exconly()
Beispiel #6
0
 async def test_channel_message_handler(self, r: redis.Redis):
     p = r.pubsub(ignore_subscribe_messages=True)
     await p.subscribe(foo=self.message_handler)
     assert await wait_for_message(p) is None
     assert await r.publish("foo", "test message") == 1
     assert await wait_for_message(p) is None
     assert self.message == make_message("message", "foo", "test message")
Beispiel #7
0
 async def test_channel_publish(self, r: redis.Redis):
     p = r.pubsub()
     await p.subscribe(self.channel)
     assert await wait_for_message(p) == self.make_message(
         "subscribe", self.channel, 1)
     await r.publish(self.channel, self.data)
     assert await wait_for_message(p) == self.make_message(
         "message", self.channel, self.data)
Beispiel #8
0
 async def test_pattern_publish(self, r: redis.Redis):
     p = r.pubsub()
     await p.psubscribe(self.pattern)
     assert await wait_for_message(p) == self.make_message(
         "psubscribe", self.pattern, 1)
     await r.publish(self.channel, self.data)
     assert await wait_for_message(p) == self.make_message(
         "pmessage", self.channel, self.data, pattern=self.pattern)
Beispiel #9
0
    async def test_context_manager(self, r: redis.Redis):
        async with r.pubsub() as pubsub:
            await pubsub.subscribe("foo")
            assert pubsub.connection is not None

        assert pubsub.connection is None
        assert pubsub.channels == {}
        assert pubsub.patterns == {}
Beispiel #10
0
 async def test_connection_error_raised_when_connection_dies(self, r: redis.Redis):
     p = r.pubsub()
     await p.subscribe("foo")
     assert await wait_for_message(p) == make_message("subscribe", "foo", 1)
     for client in await r.client_list():
         if client["cmd"] == "subscribe":
             await r.client_kill_filter(_id=client["id"])
     with pytest.raises(ConnectionError):
         await wait_for_message(p)
Beispiel #11
0
 async def test_pattern_message_handler(self, r: redis.Redis):
     p = r.pubsub(ignore_subscribe_messages=True)
     await p.psubscribe(**{"f*": self.message_handler})
     assert await wait_for_message(p) is None
     assert await r.publish("foo", "test message") == 1
     assert await wait_for_message(p) is None
     assert self.message == make_message(
         "pmessage", "foo", "test message", pattern="f*"
     )
Beispiel #12
0
    async def test_channel_subscribe_unsubscribe(self, r: redis.Redis):
        p = r.pubsub()
        await p.subscribe(self.channel)
        assert await wait_for_message(p) == self.make_message(
            "subscribe", self.channel, 1)

        await p.unsubscribe(self.channel)
        assert await wait_for_message(p) == self.make_message(
            "unsubscribe", self.channel, 0)
Beispiel #13
0
 async def test_unicode_channel_message_handler(self, r: redis.Redis):
     p = r.pubsub(ignore_subscribe_messages=True)
     channel = "uni" + chr(4456) + "code"
     channels = {channel: self.message_handler}
     await p.subscribe(**channels)
     assert await wait_for_message(p) is None
     assert await r.publish(channel, "test message") == 1
     assert await wait_for_message(p) is None
     assert self.message == make_message("message", channel, "test message")
Beispiel #14
0
    async def test_published_message_to_channel(self, r: redis.Redis):
        p = r.pubsub()
        await p.subscribe("foo")
        assert await wait_for_message(p) == make_message("subscribe", "foo", 1)
        assert await r.publish("foo", "test message") == 1

        message = await wait_for_message(p)
        assert isinstance(message, dict)
        assert message == make_message("message", "foo", "test message")
Beispiel #15
0
    async def test_pattern_subscribe_unsubscribe(self, r: redis.Redis):
        p = r.pubsub()
        await p.psubscribe(self.pattern)
        assert await wait_for_message(p) == self.make_message(
            "psubscribe", self.pattern, 1)

        await p.punsubscribe(self.pattern)
        assert await wait_for_message(p) == self.make_message(
            "punsubscribe", self.pattern, 0)
Beispiel #16
0
 async def test_unicode_pattern_message_handler(self, r: redis.Redis):
     p = r.pubsub(ignore_subscribe_messages=True)
     pattern = "uni" + chr(4456) + "*"
     channel = "uni" + chr(4456) + "code"
     await p.psubscribe(**{pattern: self.message_handler})
     assert await wait_for_message(p) is None
     assert await r.publish(channel, "test message") == 1
     assert await wait_for_message(p) is None
     assert self.message == make_message(
         "pmessage", channel, "test message", pattern=pattern
     )
Beispiel #17
0
    async def test_channel_message_handler(self, r: redis.Redis):
        p = r.pubsub(ignore_subscribe_messages=True)
        await p.subscribe(**{self.channel: self.message_handler})
        assert await wait_for_message(p) is None
        await r.publish(self.channel, self.data)
        assert await wait_for_message(p) is None
        assert self.message == self.make_message("message", self.channel, self.data)

        # test that we reconnected to the correct channel
        self.message = None
        await p.connection.disconnect()
        assert await wait_for_message(p) is None  # should reconnect
        new_data = self.data + "new data"
        await r.publish(self.channel, new_data)
        assert await wait_for_message(p) is None
        assert self.message == self.make_message("message", self.channel, new_data)
Beispiel #18
0
    async def test_ignore_all_subscribe_messages(self, r: redis.Redis):
        p = r.pubsub(ignore_subscribe_messages=True)

        checks = (
            (p.subscribe, "foo"),
            (p.unsubscribe, "foo"),
            (p.psubscribe, "f*"),
            (p.punsubscribe, "f*"),
        )

        assert p.subscribed is False
        for func, channel in checks:
            assert await func(channel) is None
            assert p.subscribed is True
            assert await wait_for_message(p) is None
        assert p.subscribed is False
Beispiel #19
0
    async def test_exception_handler(self, r: redis.Redis):
        def exception_handler_callback(e, pubsub) -> None:
            assert pubsub == p
            exceptions.put_nowait(e)

        exceptions = asyncio.Queue()
        p = r.pubsub()
        await self._subscribe(p, foo=lambda x: None)
        with mock.patch.object(p, "get_message", side_effect=Exception("error")):
            task = asyncio.get_event_loop().create_task(
                p.run(exception_handler=exception_handler_callback)
            )
            e = await exceptions.get()
            task.cancel()
            try:
                await task
            except asyncio.CancelledError:
                pass
        assert str(e) == "error"
Beispiel #20
0
    async def test_callbacks(self, r: redis.Redis):
        def callback(message):
            messages.put_nowait(message)

        messages = asyncio.Queue()
        p = r.pubsub()
        await self._subscribe(p, foo=callback)
        task = asyncio.get_event_loop().create_task(p.run())
        await r.publish("foo", "bar")
        message = await messages.get()
        task.cancel()
        try:
            await task
        except asyncio.CancelledError:
            pass
        assert message == {
            "channel": b"foo",
            "data": b"bar",
            "pattern": None,
            "type": "message",
        }
Beispiel #21
0
    async def test_published_message_to_pattern(self, r: redis.Redis):
        p = r.pubsub()
        await p.subscribe("foo")
        await p.psubscribe("f*")
        assert await wait_for_message(p) == make_message("subscribe", "foo", 1)
        assert await wait_for_message(p) == make_message("psubscribe", "f*", 2)
        # 1 to pattern, 1 to channel
        assert await r.publish("foo", "test message") == 2

        message1 = await wait_for_message(p)
        message2 = await wait_for_message(p)
        assert isinstance(message1, dict)
        assert isinstance(message2, dict)

        expected = [
            make_message("message", "foo", "test message"),
            make_message("pmessage", "foo", "test message", pattern="f*"),
        ]

        assert message1 in expected
        assert message2 in expected
        assert message1 != message2
Beispiel #22
0
 async def test_resubscribe_to_patterns_on_reconnection(
         self, r: redis.Redis):
     kwargs = make_subscribe_test_data(r.pubsub(), "pattern")
     await self._test_resubscribe_on_reconnection(**kwargs)
Beispiel #23
0
 async def test_get_message_with_timeout_returns_none(self, r: redis.Redis):
     p = r.pubsub()
     await p.subscribe("foo")
     assert await wait_for_message(p) == make_message("subscribe", "foo", 1)
     assert await p.get_message(timeout=0.01) is None
Beispiel #24
0
 async def test_pubsub_numpat(self, r: redis.Redis):
     p = r.pubsub()
     await p.psubscribe("*oo", "*ar", "b*z")
     for i in range(3):
         assert (await wait_for_message(p))["type"] == "psubscribe"
     assert await r.pubsub_numpat() == 3
Beispiel #25
0
 async def test_channel_subscribe(self, r: redis.Redis):
     r = redis.Redis(host="localhost", port=6390)
     p = r.pubsub()
     with pytest.raises(ConnectionError):
         await p.subscribe("foo")
Beispiel #26
0
    async def test_reconnect_listen(self, r: redis.Redis):
        """
        Test that a loop processing PubSub messages can survive
        a disconnect, by issuing a connect() call.
        """
        messages = asyncio.Queue()
        pubsub = r.pubsub()
        interrupt = False

        async def loop():
            # must make sure the task exits
            async with async_timeout.timeout(2):
                nonlocal interrupt
                await pubsub.subscribe("foo")
                while True:
                    # print("loop")
                    try:
                        try:
                            await pubsub.connect()
                            await loop_step()
                            # print("succ")
                        except redis.ConnectionError:
                            await asyncio.sleep(0.1)
                    except asyncio.CancelledError:
                        # we use a cancel to interrupt the "listen"
                        # when we perform a disconnect
                        # print("cancel", interrupt)
                        if interrupt:
                            interrupt = False
                        else:
                            raise

        async def loop_step():
            # get a single message via listen()
            async for message in pubsub.listen():
                await messages.put(message)
                break

        task = asyncio.get_event_loop().create_task(loop())
        # get the initial connect message
        async with async_timeout.timeout(1):
            message = await messages.get()
        assert message == {
            "channel": b"foo",
            "data": 1,
            "pattern": None,
            "type": "subscribe",
        }
        # now, disconnect the connection.
        await pubsub.connection.disconnect()
        interrupt = True
        task.cancel()  # interrupt the listen call
        # await another auto-connect message
        message = await messages.get()
        assert message == {
            "channel": b"foo",
            "data": 1,
            "pattern": None,
            "type": "subscribe",
        }
        task.cancel()
        with pytest.raises(asyncio.CancelledError):
            await task
Beispiel #27
0
 async def test_subscribe_property_with_channels(self, r: redis.Redis):
     kwargs = make_subscribe_test_data(r.pubsub(), "channel")
     await self._test_subscribed_property(**kwargs)
Beispiel #28
0
 async def test_channel_subscribe_unsubscribe(self, r: redis.Redis):
     kwargs = make_subscribe_test_data(r.pubsub(), "channel")
     await self._test_subscribe_unsubscribe(**kwargs)
Beispiel #29
0
 async def test_pattern_subscribe_unsubscribe(self, r: redis.Redis):
     kwargs = make_subscribe_test_data(r.pubsub(), "pattern")
     await self._test_subscribe_unsubscribe(**kwargs)
Beispiel #30
0
 async def test_subscribe_property_with_patterns(self, r: redis.Redis):
     kwargs = make_subscribe_test_data(r.pubsub(), "pattern")
     await self._test_subscribed_property(**kwargs)