async def test_pub_sub_with_all_topics(server): """ Check client gets event when subscribing via ALL_TOPICS """ # finish trigger finish = asyncio.Event() # Create a client and subscribe to topics async with PubSubClient() as client: async def on_event(data, topic): assert data == DATA finish.set() # subscribe for the event client.subscribe(ALL_TOPICS, on_event) # start listentining client.start_client(uri) # wait for the client to be ready to receive events await client.wait_until_ready() # publish events (with sync=False toa void deadlocks waiting on the publish to ourselves) published = await client.publish( [EVENT_TOPIC], data=DATA, sync=False, notifier_id=gen_uid() ) assert published.result # wait for finish trigger await asyncio.wait_for(finish.wait(), 5)
def __init__(self, broadcast_url: str, notifier: EventNotifier, channel="EventNotifier", broadcast_type=None, is_publish_only=False) -> None: """ Args: broadcast_url (str): the URL of the broadcasting service notifier (EventNotifier): the event notifier managing our internal events - which will be bridge via the broadcaster channel (str, optional): Channel name. Defaults to "EventNotifier". broadcast_type (Broadcast, optional): Broadcast class to use. None - Defaults to Broadcast. is_publish_only (bool, optional): [For default context] Should the broadcaster only transmit events and not listen to any. Defaults to False """ # Broadcast init params self._broadcast_url = broadcast_url self._broadcast_type = broadcast_type or Broadcast # Publish broadcast (initialized within async with statement) self._sharing_broadcast_channel = None # channel to operate on self._channel = channel # Async-io task for reading broadcasts (initialized within async with statement) self._subscription_task = None # Uniqueue instance id (used to avoid reading own notifications sent in broadcast) self._id = gen_uid() # The internal events notifier self._notifier = notifier self._is_publish_only = is_publish_only self._publish_lock = None # used to track creation / removal of resources needed per type (reader task->listen, and subscription to internal events->share) self._listen_count: int = 0 self._share_count: int = 0 # If we opt to manage the context directly (i.e. call async with on the event broadcaster itself) self._context_manager = None
async def test_immediate_server_disconnect(server): """ Test reconnecting when a server hangups on connect """ # finish trigger finish = asyncio.Event() # Create a client and subscribe to topics async with PubSubClient() as client: async def on_event(data, topic): assert data == DATA finish.set() # subscribe for the event client.subscribe(EVENT_TOPIC, on_event) # start listentining client.start_client(uri) # wait for the client to be ready to receive events await client.wait_until_ready() # publish events (with sync=False toa void deadlocks waiting on the publish to ourselves) published = await client.publish([EVENT_TOPIC], data=DATA, sync=False, notifier_id=gen_uid()) assert published.result == True # wait for finish trigger await asyncio.wait_for(finish.wait(), 5)
def __init__(self, broadcast_url: str, notifier: EventNotifier, channel="EventNotifier", broadcast_type=None, is_publish_only=False) -> None: """ Args: broadcast_url (str): the URL of the broadcasting service notifier (EventNotifier): the event notifier managing our internal events - which will be bridge via the broadcaster channel (str, optional): Channel name. Defaults to "EventNotifier". broadcast_type (Broadcast, optional): Broadcast class to use. None - Defaults to Broadcast. is_publish_only (bool, optional): Should the broadcaster only transmit events and not listen to any. Defaults to False """ # Broadcast init params self._broadcast_url = broadcast_url self._broadcast_type = broadcast_type or Broadcast # Publish broadcast (initialized within async with statement) self._broadcast = None # channel to operate on self._channel = channel # Async-io task for reading broadcasts (initialized within async with statement) self._subscription_task = None # Uniqueue instance id (used to avoid reading own notifications sent in broadcast) self._id = gen_uid() # The internal events notifier self._notifier = notifier self._is_publish_only = is_publish_only self._lock = asyncio.Lock() self._publish_lock = asyncio.Lock() self._num_connections = 0
async def test_pub_sub_with_all_topics_with_remote_id_on(server): """ same as the basic_test::test_pub_sub_with_all_topics, but this time makes sure that the rpc_channel_get_remote_id doesn't break anything. """ # finish trigger finish = asyncio.Event() # Create a client and subscribe to topics async with PubSubClient() as client: async def on_event(data, topic): assert data == DATA finish.set() # subscribe for the event client.subscribe(ALL_TOPICS, on_event) # start listentining client.start_client(uri) # wait for the client to be ready to receive events await client.wait_until_ready() # publish events (with sync=False toa void deadlocks waiting on the publish to ourselves) published = await client.publish([EVENT_TOPIC], data=DATA, sync=False, notifier_id=gen_uid()) assert published.result # wait for finish trigger await asyncio.wait_for(finish.wait(), 5)
async def on_connect(client, channel): try: print("Connected") # publish events (with sync=False to avoid deadlocks waiting on the publish to ourselves) published = await client.publish([EVENT_TOPIC], data=DATA, sync=False, notifier_id=gen_uid()) assert published.result == True except RpcChannelClosedException: # expected pass
async def test_disconnect_callback_without_context(delayed_death_server): """ Test reconnecting when a server hangups AFTER connect and that the disconnect callback work """ # finish trigger finish = asyncio.Event() disconnected = asyncio.Event() async def on_disconnect(channel): disconnected.set() async def on_connect(client, channel): try: print("Connected") # publish events (with sync=False to avoid deadlocks waiting on the publish to ourselves) published = await client.publish([EVENT_TOPIC], data=DATA, sync=False, notifier_id=gen_uid()) assert published.result == True except RpcChannelClosedException: # expected pass # Create a client and subscribe to topics client = PubSubClient(on_disconnect=[on_disconnect], on_connect=[on_connect]) async def on_event(data, topic): assert data == DATA finish.set() # subscribe for the event client.subscribe(EVENT_TOPIC, on_event) # start listentining client.start_client(uri) # wait for the client to be ready to receive events await client.wait_until_ready() # publish events (with sync=False toa void deadlocks waiting on the publish to ourselves) published = await client.publish([EVENT_TOPIC], data=DATA, sync=False, notifier_id=gen_uid()) assert published.result == True # wait for finish trigger await asyncio.wait_for(finish.wait(), 5) await client.disconnect() await asyncio.wait_for(disconnected.wait(), 1) assert disconnected.is_set()
from fastapi import (APIRouter, FastAPI, WebSocket) import uvicorn import pytest from multiprocessing import Process import asyncio import os import sys # Add parent path to use local src as package for tests sys.path.append( os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) # Configurable PORT = int(os.environ.get("PORT") or "9000") # Random ID CLIENT_ID = gen_uid() uri = f"ws://localhost:{PORT}/ws/{CLIENT_ID}" class RpcCalculator(RpcMethodsBase): async def add(self, a: float, b: float) -> float: return a + b async def multiply(self, a: float, b: float) -> float: return a * b def setup_calc_server(): app = FastAPI() router = APIRouter() # expose calculator methods
def gen_subscription_id(self): return gen_uid()
def gen_subscriber_id(self): return gen_uid()