Repository: aio-libs-abandoned/aioredis-py

Issue:
Fixed ConnectionsPool.[pubsub_channels/pubsub_patterns]
Fixed bug in `commands.pubsub.PubSubCommandsMixin.subscribe` (and psubscribe). `ConnectionsPool.pubsub_channles` code was called before `ConnectionsPool._pubsub_conn` creation, and therefore `pubsub_channles` 


Discussion:
# [Codecov](https://codecov.io/gh/aio-libs/aioredis/pull/351?src=pr&el=h1) Report
> Merging [#351](https://codecov.io/gh/aio-libs/aioredis/pull/351?src=pr&el=desc) into [master](https://codecov.io/gh/aio-libs/aioredis/commit/5f44b2ae03146706cea03505072c6dba8e684f58?src=pr&el=desc) will **decrease** coverage by `0.02%`.
> The diff coverage is `80%`.

[![Impacted file tree graph](https://codecov.io/gh/aio-libs/aioredis/pull/351/graphs/tree.svg?token=THCDhqngRB&src=pr&height=150&width=650)](https://codecov.io/gh/aio-libs/aioredis/pull/351?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #351      +/-   ##
==========================================
- Coverage   96.86%   96.84%   -0.03%     
==========================================
  Files          54       54              
  Lines        7309     7319      +10     
  Branches      519      519              
==========================================
+ Hits         7080     7088       +8     
- Misses        168      169       +1     
- Partials       61       62       +1
```


| [Impacted Files](https://codecov.io/gh/aio-libs/aioredis/pull/351?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [aioredis/util.py](https://codecov.io/gh/aio-libs/aioredis/pull/351/diff?src=pr&el=tree#diff-YWlvcmVkaXMvdXRpbC5weQ==) | `94.07% <80%> (-1.13%)` | :arrow_down: |
| [tests/sentinel\_failover\_test.py](https://codecov.io/gh/aio-libs/aioredis/pull/351/diff?src=pr&el=tree#diff-dGVzdHMvc2VudGluZWxfZmFpbG92ZXJfdGVzdC5weQ==) | `86.46% <0%> (-1.51%)` | :arrow_down: |
| [aioredis/sentinel/pool.py](https://codecov.io/gh/aio-libs/aioredis/pull/351/diff?src=pr&el=tree#diff-YWlvcmVkaXMvc2VudGluZWwvcG9vbC5weQ==) | `80.22% <0%> (+0.76%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/aio-libs/aioredis/pull/351?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/aio-libs/aioredis/pull/351?src=pr&el=footer). Last update [5f44b2a...ea6d5da](https://codecov.io/gh/aio-libs/aioredis/pull/351?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Resolving patch:
diff --git a/aioredis/commands/pubsub.py b/aioredis/commands/pubsub.py
--- a/aioredis/commands/pubsub.py
+++ b/aioredis/commands/pubsub.py
@@ -29,7 +29,7 @@ def subscribe(self, channel, *channels):
         conn = self._pool_or_conn
         return wait_return_channels(
             conn.execute_pubsub(b'SUBSCRIBE', channel, *channels),
-            conn.pubsub_channels)
+            conn, 'pubsub_channels')
 
     def unsubscribe(self, channel, *channels):
         """Unsubscribe from specific channels.
@@ -52,7 +52,7 @@ def psubscribe(self, pattern, *patterns):
         conn = self._pool_or_conn
         return wait_return_channels(
             conn.execute_pubsub(b'PSUBSCRIBE', pattern, *patterns),
-            conn.pubsub_patterns)
+            conn, 'pubsub_patterns')
 
     def punsubscribe(self, pattern, *patterns):
         """Unsubscribe from specific patterns.
@@ -103,6 +103,7 @@ def in_pubsub(self):
         return self._pool_or_conn.in_pubsub
 
 
-async def wait_return_channels(fut, channels_dict):
-    return [channels_dict[name]
-            for cmd, name, count in await fut]
+async def wait_return_channels(fut, conn, field):
+    res = await fut
+    channels_dict = getattr(conn, field)
+    return [channels_dict[name] for cmd, name, count in res]


Test patch:
diff --git a/tests/pubsub_commands_test.py b/tests/pubsub_commands_test.py
--- a/tests/pubsub_commands_test.py
+++ b/tests/pubsub_commands_test.py
@@ -1,5 +1,6 @@
 import asyncio
 import pytest
+import aioredis
 
 
 async def _reader(channel, output, waiter, conn):
@@ -62,6 +63,30 @@ async def test_subscribe(redis):
                    [b'unsubscribe', b'chan:2', 0]]
 
 
+@pytest.mark.parametrize('create_redis', [
+    pytest.param(aioredis.create_redis_pool, id='pool'),
+])
+@pytest.mark.run_loop
+async def test_subscribe_empty_pool(create_redis, server, loop, _closable):
+    redis = await create_redis(server.tcp_address, loop=loop)
+    _closable(redis)
+    await redis.connection.clear()
+
+    res = await redis.subscribe('chan:1', 'chan:2')
+    assert redis.in_pubsub == 2
+
+    ch1 = redis.channels['chan:1']
+    ch2 = redis.channels['chan:2']
+
+    assert res == [ch1, ch2]
+    assert ch1.is_pattern is False
+    assert ch2.is_pattern is False
+
+    res = await redis.unsubscribe('chan:1', 'chan:2')
+    assert res == [[b'unsubscribe', b'chan:1', 1],
+                   [b'unsubscribe', b'chan:2', 0]]
+
+
 @pytest.mark.run_loop
 async def test_psubscribe(redis, create_redis, server, loop):
     sub = redis
@@ -85,6 +110,34 @@ async def test_psubscribe(redis, create_redis, server, loop):
                    ]
 
 
+@pytest.mark.parametrize('create_redis', [
+    pytest.param(aioredis.create_redis_pool, id='pool'),
+])
+@pytest.mark.run_loop
+async def test_psubscribe_empty_pool(create_redis, server, loop, _closable):
+    sub = await create_redis(server.tcp_address, loop=loop)
+    pub = await create_redis(server.tcp_address, loop=loop)
+    _closable(sub)
+    _closable(pub)
+    await sub.connection.clear()
+    res = await sub.psubscribe('patt:*', 'chan:*')
+    assert sub.in_pubsub == 2
+
+    pat1 = sub.patterns['patt:*']
+    pat2 = sub.patterns['chan:*']
+    assert res == [pat1, pat2]
+
+    await pub.publish_json('chan:123', {"Hello": "World"})
+    res = await pat2.get_json()
+    assert res == (b'chan:123', {"Hello": "World"})
+
+    res = await sub.punsubscribe('patt:*', 'patt:*', 'chan:*')
+    assert res == [[b'punsubscribe', b'patt:*', 1],
+                   [b'punsubscribe', b'patt:*', 1],
+                   [b'punsubscribe', b'chan:*', 0],
+                   ]
+
+
 @pytest.redis_version(
     2, 8, 0, reason='PUBSUB CHANNELS is available since redis>=2.8.0')
 @pytest.mark.run_loop