Skip to content

Commit c29df3f

Browse files
committed
Fix tests
1 parent 3e88551 commit c29df3f

File tree

7 files changed

+116
-69
lines changed

7 files changed

+116
-69
lines changed

pubnub/pubnub_asyncio.py

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -761,25 +761,35 @@ def presence(self, pubnub, presence):
761761
"""
762762
self.presence_queue.put_nowait(presence)
763763

764-
async def _wait_for(self, coro):
764+
async def _wait_for(self, coro, timeout=30):
765765
"""Wait for a coroutine to complete.
766766
767767
Args:
768768
coro: The coroutine to wait for
769+
timeout: Maximum time to wait in seconds (default: 30)
769770
770771
Returns:
771772
The result of the coroutine
772773
773774
Raises:
775+
asyncio.TimeoutError: If the operation times out
774776
Exception: If an error occurs while waiting
775777
"""
776778
scc_task = asyncio.ensure_future(coro)
777779
err_task = asyncio.ensure_future(self.error_queue.get())
778780

779-
await asyncio.wait([
781+
done, pending = await asyncio.wait([
780782
scc_task,
781783
err_task
782-
], return_when=asyncio.FIRST_COMPLETED)
784+
], return_when=asyncio.FIRST_COMPLETED, timeout=timeout)
785+
786+
# Handle timeout
787+
if not done:
788+
if not scc_task.cancelled():
789+
scc_task.cancel()
790+
if not err_task.cancelled():
791+
err_task.cancel()
792+
raise asyncio.TimeoutError(f"Operation timed out after {timeout} seconds")
783793

784794
if err_task.done() and not scc_task.done():
785795
if not scc_task.cancelled():
@@ -790,44 +800,73 @@ async def _wait_for(self, coro):
790800
err_task.cancel()
791801
return scc_task.result()
792802

793-
async def wait_for_connect(self):
794-
"""Wait for a connection to be established."""
803+
async def wait_for_connect(self, timeout=30):
804+
"""Wait for a connection to be established.
805+
806+
Args:
807+
timeout: Maximum time to wait in seconds (default: 30)
808+
809+
Raises:
810+
asyncio.TimeoutError: If connection is not established within timeout
811+
"""
795812
if not self.connected_event.is_set():
796-
await self._wait_for(self.connected_event.wait())
813+
await self._wait_for(self.connected_event.wait(), timeout=timeout)
814+
815+
async def wait_for_disconnect(self, timeout=30):
816+
"""Wait for a disconnection to occur.
817+
818+
Args:
819+
timeout: Maximum time to wait in seconds (default: 30)
797820
798-
async def wait_for_disconnect(self):
799-
"""Wait for a disconnection to occur."""
821+
Raises:
822+
asyncio.TimeoutError: If disconnection does not occur within timeout
823+
"""
800824
if not self.disconnected_event.is_set():
801-
await self._wait_for(self.disconnected_event.wait())
825+
await self._wait_for(self.disconnected_event.wait(), timeout=timeout)
802826

803-
async def wait_for_message_on(self, *channel_names):
827+
async def wait_for_message_on(self, *channel_names, timeout=30):
804828
"""Wait for a message on specific channels.
805829
806830
Args:
807831
*channel_names: Channel names to wait for
832+
timeout: Maximum time to wait in seconds (default: 30)
808833
809834
Returns:
810835
The message envelope when received
811836
812837
Raises:
838+
asyncio.TimeoutError: If no message is received within timeout
813839
Exception: If an error occurs while waiting
814840
"""
815841
channel_names = list(channel_names)
816842
while True:
817843
try:
818-
env = await self._wait_for(self.message_queue.get())
844+
env = await self._wait_for(self.message_queue.get(), timeout=timeout)
819845
if env.channel in channel_names:
820846
return env
821847
else:
822848
continue
823849
finally:
824850
self.message_queue.task_done()
825851

826-
async def wait_for_presence_on(self, *channel_names):
852+
async def wait_for_presence_on(self, *channel_names, timeout=30):
853+
"""Wait for a presence event on specific channels.
854+
855+
Args:
856+
*channel_names: Channel names to wait for
857+
timeout: Maximum time to wait in seconds (default: 30)
858+
859+
Returns:
860+
The presence envelope when received
861+
862+
Raises:
863+
asyncio.TimeoutError: If no presence event is received within timeout
864+
Exception: If an error occurs while waiting
865+
"""
827866
channel_names = list(channel_names)
828867
while True:
829868
try:
830-
env = await self._wait_for(self.presence_queue.get())
869+
env = await self._wait_for(self.presence_queue.get(), timeout=timeout)
831870
if env.channel in channel_names:
832871
return env
833872
else:

scripts/run-tests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
REPO_ROOT = _dname(_dname(os.path.abspath(__file__)))
1212
os.chdir(os.path.join(REPO_ROOT))
1313

14-
tcmn = 'py.test tests --cov=pubnub --ignore=tests/manual/'
14+
tcmn = 'pytest -vv tests --cov=pubnub --ignore=tests/manual/'
1515
fcmn = 'flake8 --exclude=scripts/,src/,.cache,.git,.idea,.tox,._trial_temp/,venv/ --ignore F811,E402'
1616

1717

tests/integrational/asyncio/test_change_uuid.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ async def test_change_uuid():
3030
assert isinstance(envelope.result, PNSignalResult)
3131
assert isinstance(envelope.status, PNStatus)
3232

33+
await pn.stop()
34+
3335

3436
@pn_vcr.use_cassette('tests/integrational/fixtures/asyncio/signal/uuid_no_lock.json',
3537
filter_query_parameters=['seqn', 'pnsdk', 'l_sig'], serializer='pn_json')
@@ -51,13 +53,15 @@ async def test_change_uuid_no_lock():
5153
assert isinstance(envelope.result, PNSignalResult)
5254
assert isinstance(envelope.status, PNStatus)
5355

56+
await pn.stop()
57+
5458

55-
def test_uuid_validation_at_init(_function_event_loop):
59+
def test_uuid_validation_at_init():
5660
with pytest.raises(AssertionError) as exception:
5761
pnconf = PNConfiguration()
5862
pnconf.publish_key = "demo"
5963
pnconf.subscribe_key = "demo"
60-
PubNubAsyncio(pnconf, custom_event_loop=_function_event_loop)
64+
PubNubAsyncio(pnconf)
6165

6266
assert str(exception.value) == 'UUID missing or invalid type'
6367

tests/integrational/asyncio/test_heartbeat.py

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -21,54 +21,54 @@ async def test_timeout_event_on_broken_heartbeat():
2121
listener_config = pnconf_env_copy(uuid=helper.gen_channel("listener"), enable_subscribe=True)
2222
pubnub_listener = PubNubAsyncio(listener_config)
2323

24-
# - connect to :ch-pnpres
25-
callback_presence = SubscribeListener()
26-
pubnub_listener.add_listener(callback_presence)
27-
pubnub_listener.subscribe().channels(ch).with_presence().execute()
28-
await callback_presence.wait_for_connect()
29-
30-
envelope = await callback_presence.wait_for_presence_on(ch)
31-
assert ch == envelope.channel
32-
assert 'join' == envelope.event
33-
assert pubnub_listener.uuid == envelope.uuid
34-
35-
# # - connect to :ch
36-
callback_messages = SubscribeListener()
37-
pubnub.add_listener(callback_messages)
38-
pubnub.subscribe().channels(ch).execute()
39-
40-
useless_connect_future = asyncio.ensure_future(callback_messages.wait_for_connect())
41-
presence_future = asyncio.ensure_future(callback_presence.wait_for_presence_on(ch))
42-
43-
# - assert join event
44-
await asyncio.wait([useless_connect_future, presence_future])
45-
46-
prs_envelope = presence_future.result()
47-
48-
assert ch == prs_envelope.channel
49-
assert 'join' == prs_envelope.event
50-
assert pubnub.uuid == prs_envelope.uuid
51-
# - break messenger heartbeat loop
52-
pubnub._subscription_manager._stop_heartbeat_timer()
53-
54-
# wait for one heartbeat call
55-
await asyncio.sleep(8)
56-
57-
# - assert for timeout
58-
envelope = await callback_presence.wait_for_presence_on(ch)
59-
assert ch == envelope.channel
60-
assert 'timeout' == envelope.event
61-
assert pubnub.uuid == envelope.uuid
62-
63-
pubnub.unsubscribe().channels(ch).execute()
64-
if isinstance(pubnub._subscription_manager, AsyncioSubscriptionManager):
24+
try:
25+
# - connect to :ch-pnpres
26+
callback_presence = SubscribeListener()
27+
pubnub_listener.add_listener(callback_presence)
28+
pubnub_listener.subscribe().channels(ch).with_presence().execute()
29+
await callback_presence.wait_for_connect()
30+
31+
envelope = await callback_presence.wait_for_presence_on(ch)
32+
assert ch == envelope.channel
33+
assert 'join' == envelope.event
34+
assert pubnub_listener.uuid == envelope.uuid
35+
36+
# # - connect to :ch
37+
callback_messages = SubscribeListener()
38+
pubnub.add_listener(callback_messages)
39+
pubnub.subscribe().channels(ch).execute()
40+
41+
useless_connect_future = asyncio.ensure_future(callback_messages.wait_for_connect())
42+
presence_future = asyncio.ensure_future(callback_presence.wait_for_presence_on(ch))
43+
44+
# - assert join event
45+
done, pending = await asyncio.wait([useless_connect_future, presence_future], return_when=asyncio.ALL_COMPLETED)
46+
47+
prs_envelope = presence_future.result()
48+
49+
assert ch == prs_envelope.channel
50+
assert 'join' == prs_envelope.event
51+
assert pubnub.uuid == prs_envelope.uuid
52+
# - break messenger heartbeat loop
53+
pubnub._subscription_manager._stop_heartbeat_timer()
54+
55+
# wait for one heartbeat call
56+
await asyncio.sleep(8)
57+
58+
# - assert for timeout
59+
envelope = await callback_presence.wait_for_presence_on(ch)
60+
assert ch == envelope.channel
61+
assert 'timeout' == envelope.event
62+
assert pubnub.uuid == envelope.uuid
63+
64+
pubnub.unsubscribe().channels(ch).execute()
6565
await callback_messages.wait_for_disconnect()
6666

67-
# - disconnect from :ch-pnpres
68-
pubnub_listener.unsubscribe().channels(ch).execute()
69-
if isinstance(pubnub._subscription_manager, AsyncioSubscriptionManager):
67+
# - disconnect from :ch-pnpres
68+
pubnub_listener.unsubscribe().channels(ch).execute()
7069
await callback_presence.wait_for_disconnect()
7170

72-
await pubnub.stop()
73-
await pubnub_listener.stop()
74-
await asyncio.sleep(0.5)
71+
finally:
72+
await pubnub.stop()
73+
await pubnub_listener.stop()
74+
await asyncio.sleep(0.5)

tests/integrational/asyncio/test_message_count.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import pytest
2+
import pytest_asyncio
23

34
from pubnub.pubnub_asyncio import PubNubAsyncio
45
from pubnub.models.envelopes import AsyncioEnvelope
@@ -8,12 +9,13 @@
89
from tests.integrational.vcr_helper import pn_vcr
910

1011

11-
@pytest.fixture
12-
def pn(_function_event_loop):
12+
@pytest_asyncio.fixture
13+
async def pn():
1314
config = pnconf_mc_copy()
1415
config.enable_subscribe = False
15-
pn = PubNubAsyncio(config, custom_event_loop=_function_event_loop)
16+
pn = PubNubAsyncio(config)
1617
yield pn
18+
await pn.stop()
1719

1820

1921
@pn_vcr.use_cassette(

tests/integrational/vcr_asyncio_sleeper.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ def __init__(self, raise_times):
4848

4949
super(VCR599Listener, self).__init__()
5050

51-
async def _wait_for(self, coro):
51+
async def _wait_for(self, coro, timeout=30):
5252
try:
53-
res = await super(VCR599Listener, self)._wait_for(coro)
53+
res = await super(VCR599Listener, self)._wait_for(coro, timeout=timeout)
5454
return res
5555
except CannotOverwriteExistingCassetteException as e:
5656
if "Can't overwrite existing cassette" in str(e):

tests/pytest.ini

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ filterwarnings =
66
ignore:The function .* is deprecated. Use.* Include Object instead:DeprecationWarning
77
ignore:The function .* is deprecated. Use.* PNUserMember class instead:DeprecationWarning
88

9-
asyncio_default_fixture_loop_scope = module
9+
asyncio_default_fixture_loop_scope = function
10+
timeout = 60
11+
timeout_func_only = true

0 commit comments

Comments
 (0)