refactor: add shared pubsub test fixtures and wait_for polling helper#1298
refactor: add shared pubsub test fixtures and wait_for polling helper#1298yashksaini-coder wants to merge 2 commits intolibp2p:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds shared pubsub test infrastructure to support the upcoming pubsub test suite refactor (per #378), centralizing synchronization helpers and common gossipsub fixtures/context managers.
Changes:
- Introduce
tests/utils/pubsub/wait.pywith reusable polling (wait_for) and multi-node convergence (wait_for_convergence) helpers. - Add
tests/core/pubsub/conftest.pywith aGossipSubHarnesswrapper plus context managers/fixtures for creating connected/subscribed gossipsub nodes. - Refactor
test_dummyaccount_demo.pyto reuse the shared convergence helper and rely on globaltrio_mode = trueinstead of per-test@pytest.mark.trio.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| tests/utils/pubsub/wait.py | New shared polling/convergence utilities for pubsub test synchronization. |
| tests/core/pubsub/conftest.py | New shared harness + context managers/fixtures for creating connected/subscribed GossipSub test topologies. |
| tests/core/pubsub/test_dummyaccount_demo.py | Swaps inline convergence helper for shared import; removes redundant trio markers. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| _is_async = inspect.iscoroutinefunction(predicate) | ||
| start = trio.current_time() | ||
| last_exc: Exception | None = None | ||
|
|
||
| while True: | ||
| try: | ||
| result = (await predicate()) if _is_async else predicate() # type: ignore[misc] | ||
| if result: |
There was a problem hiding this comment.
wait_for() determines async-ness via inspect.iscoroutinefunction(predicate), which misses common patterns like lambda: async_fn() or functools.partial(async_fn, ...). In those cases predicate() returns a coroutine object (truthy) and the helper will return immediately without awaiting it, potentially causing false positives and "coroutine was never awaited" warnings. Consider calling predicate() each loop and then await if the returned value is awaitable (e.g., inspect.isawaitable(result)), and update the type hint accordingly to avoid the type: ignore.
| async with gossipsub_nodes(n, **kwargs) as harness: | ||
| await dense_connect(harness.hosts) | ||
| await trio.sleep(0.1) |
There was a problem hiding this comment.
connected_gossipsub_nodes() uses a fixed trio.sleep(0.1) after dense_connect(). This makes the fixture timing-dependent and can still be flaky (or unnecessarily slow) since pubsub peer registration is asynchronous; the codebase already has event-based helpers like Pubsub.wait_for_peer() intended to replace arbitrary sleeps. Suggest replacing the fixed sleep with a deterministic wait (e.g., wait until each pubsub observes at least one peer when n > 1, or otherwise expose a configurable settle/wait strategy) so the fixture actually guarantees “connected” semantics.
| async with gossipsub_nodes(n, **kwargs) as harness: | |
| await dense_connect(harness.hosts) | |
| await trio.sleep(0.1) | |
| peer_wait_timeout = kwargs.pop("peer_wait_timeout", 5.0) | |
| async with gossipsub_nodes(n, **kwargs) as harness: | |
| await dense_connect(harness.hosts) | |
| if n > 1: | |
| with trio.fail_after(peer_wait_timeout): | |
| for index, pubsub in enumerate(harness.pubsubs): | |
| target_host = harness.hosts[(index + 1) % n] | |
| await pubsub.wait_for_peer(target_host.get_id()) |
Summary
Introduces shared test infrastructure for the pubsub test suite restructuring (PR 1 of 6 per the plan in #378):
tests/utils/pubsub/wait.py—wait_for()generic polling helper andwait_for_convergence()multi-node convergence helper, replacing inline definitionstests/core/pubsub/conftest.py—GossipSubHarnessdataclass with.pubsubs,.hosts,.routersproperties, plusgossipsub_nodes(),connected_gossipsub_nodes(),subscribed_mesh()context managers and aconnected_gossipsub_pairfixturetests/core/pubsub/test_dummyaccount_demo.py— migrated to importwait_for_convergencefrom the shared module; removed 9 redundant@pytest.mark.triodecorators (covered bytrio_mode = truein pyproject.toml)This lays the foundation for subsequent PRs that will replace ~253 synchronization sleeps, standardize router extraction, flatten class-based tests, consolidate overlapping files, and tag slow tests.
Test plan
test_dummyaccount_demo.pypassconftest.pyCloses #378
cc @IronJam11 @seetadev