def test_alt_call_tracking_header(fsip): '''Test that an alternate `EventListener.call_tracking_header` (in this case using the 'Caller-Destination-Number' channel variable) can be used to associate sessions into calls. ''' with sync_caller(fsip) as caller: # use the destination number as the call association var caller.client.listener.call_tracking_header = 'Caller-Destination-Number' dest = 'doggy' # have the external prof call itself by default sess, waitfor = caller( "{}@{}:{}".format(dest, caller.client.host, 5080), 'TonePlay', # the default app timeout=3, ) assert sess.is_outbound() # call should be indexed by the req uri username assert dest in caller.client.listener.calls call = caller.client.listener.calls[dest] time.sleep(1) assert call.first is sess assert call.last call.hangup() time.sleep(0.1) assert caller.client.listener.count_calls() == 0
def test_coro_timeout(fsip): """Verify that if a call never receives an event which is being waited that the waiting coroutine is cancelled at call hangup. """ class MyApp: @coroutine("CHANNEL_CREATE") async def timeout_on_hangup(self, sess): # should never arrive since we don't subscribe for the event type if sess.is_inbound(): await sess.answer() sess.vars['answered'] = True await sess.recv("CHANNEL_HANGUP", timeout=1) with sync_caller(fsip, apps={"MyApp": MyApp}) as caller: # have the external prof call itself by default assert 'MyApp' in caller.app_names sess, waitfor = caller( "doggy@{}:{}".format(caller.client.host, 5080), 'MyApp', timeout=3, ) assert sess.is_outbound() callee = sess.call.get_peer(sess) callee_futs = callee._futures waitfor(callee, 'answered', timeout=0.2) # answer future should be popped assert not callee_futs.get('CHANNEL_ANSWER') hangup_fut = callee_futs.get('CHANNEL_HANGUP') assert hangup_fut time.sleep(1) # wait for timeout task = callee.tasks.pop(hangup_fut)[0] assert task.done() with pytest.raises(asyncio.TimeoutError): task.result()
def test_toneplay(fsip): '''Test the synchronous caller with a simple toneplay ''' with sync_caller(fsip, apps={"TonePlay": TonePlay}) as caller: # have the external prof call itself by default assert 'TonePlay' in caller.app_names sess, waitfor = caller( "doggy@{}:{}".format(caller.client.host, 5080), 'TonePlay', timeout=3, ) assert sess.is_outbound() time.sleep(1) sess.hangup() time.sleep(0.1) assert caller.client.listener.count_calls() == 0
def test_playrec(fsip): '''Test the synchronous caller with a simulated conversation using the the `PlayRec` app. Currently this test does no audio checking but merely verifies the callback chain is invoked as expected. ''' with sync_caller(fsip, apps={"PlayRec": PlayRec}) as caller: # have the external prof call itself by default caller.apps.PlayRec['PlayRec'].rec_rate = 1 sess, waitfor = caller( "doggy@{}:{}".format(caller.client.host, 5080), 'PlayRec', timeout=10, ) waitfor(sess, 'recorded', timeout=15) waitfor(sess.call.get_peer(sess), 'recorded', timeout=15) assert sess.call.vars['record'] time.sleep(1) assert sess.hungup
def test_untracked_call(fsip): with sync_caller(fsip) as caller: # use an invalid chan var for call tracking caller.client.listener.call_tracking_header = 'doggypants' # have the external prof call itself by default sess, waitfor = caller( "{}@{}:{}".format('jonesy', caller.client.host, 5080), 'TonePlay', # the default app timeout=3, ) # calls should be created for both inbound and outbound sessions # since our tracking variable is nonsense l = caller.client.listener # assert len(l.sessions) == len(l.calls) == 2 assert l.count_sessions() == l.count_calls() == 2 sess.hangup() time.sleep(0.1) # no calls or sessions should be active assert l.count_sessions() == l.count_calls() == 0 assert not l.sessions and not l.calls
def test_coro_cancel(fsip): """Verify that if a call never receives an event which is being waited that the waiting coroutine is cancelled at call hangup. """ class MyApp: @coroutine("CHANNEL_CREATE") async def wait_on_bridge(self, sess): # should never arrive since we don't subscribe for the event type if sess.is_inbound(): sess.answer() await sess.recv("CHANNEL_ANSWER") await sess.recv("CHANNEL_BRIDGE") with sync_caller(fsip, apps={"MyApp": MyApp}) as caller: # have the external prof call itself by default assert 'MyApp' in caller.app_names sess, waitfor = caller( "doggy@{}:{}".format(caller.client.host, 5080), 'MyApp', timeout=3, ) assert sess.is_outbound() callee = sess.call.get_peer(sess) callee_futs = callee._futures assert callee_futs # answer fut should be inserted time.sleep(0.1) # wait for answer # answer future should be consumed already assert not callee_futs.get('CHANNEL_ANSWER', None) br_fut = callee_futs['CHANNEL_BRIDGE'] assert not br_fut.done() time.sleep(0.1) # ensure our coroutine has been scheduled task = callee.tasks[br_fut][0] el = caller.client.listener assert task in el.event_loop.get_tasks() sess.hangup() time.sleep(0.1) # wait for hangup assert br_fut.cancelled() assert not callee._futures # should be popped by done callback assert el.count_calls() == 0