Author: mmichelson
Date: Wed Jan 14 15:15:42 2015
New Revision: 6282

URL: http://svnview.digium.com/svn/testsuite?view=rev&rev=6282
Log:
Add a test for remote attended transfers.

This sets up two Asterisk boxes and a single PJSUA "phone". The PJSUA
endpoint has simultaneous conversations with parties on both Asterisk boxes
and places an attended transfer in order to link the Asterisk boxes directly
together. This test ensures that it goes smoothly.

Review: https://reviewboard.asterisk.org/r/4317


Added:
    
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/
    
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/
    
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/
    
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/extensions.conf
   (with props)
    
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/pjsip.conf
   (with props)
    
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/
    
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/extensions.conf
   (with props)
    
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/pjsip.conf
   (with props)
    
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/test-config.yaml
   (with props)
    
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/transfer.py
   (with props)
Modified:
    asterisk/trunk/lib/python/asterisk/pjsua_mod.py
    
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/tests.yaml

Modified: asterisk/trunk/lib/python/asterisk/pjsua_mod.py
URL: 
http://svnview.digium.com/svn/testsuite/asterisk/trunk/lib/python/asterisk/pjsua_mod.py?view=diff&rev=6282&r1=6281&r2=6282
==============================================================================
--- asterisk/trunk/lib/python/asterisk/pjsua_mod.py (original)
+++ asterisk/trunk/lib/python/asterisk/pjsua_mod.py Wed Jan 14 15:15:42 2015
@@ -113,7 +113,7 @@
         self.lib = None
         self.num_regs = 0
         self.num_accts = 0
-        self.ami = None
+        self.ami_connected = 0
         self.callback_module = instance_config['callback_module']
         self.callback_method = instance_config['callback_method']
 
@@ -124,7 +124,13 @@
         We use AMI connection as the signal to start creating PJSUA accounts
         and starting PJLIB.
         """
-        self.ami = ami
+        self.ami_connected += 1
+        if (self.ami_connected < len(self.test_object.ami)):
+            LOGGER.info("{0} ami connected. Waiting for "
+                        "{1}".format(self.ami_connected,
+                                     len(self.test_object.ami)))
+            return
+
         self.lib = pj.Lib()
         try:
             self.lib.init()

Added: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/extensions.conf
URL: 
http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/extensions.conf?view=auto&rev=6282
==============================================================================
--- 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/extensions.conf
 (added)
+++ 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/extensions.conf
 Wed Jan 14 15:15:42 2015
@@ -1,0 +1,9 @@
+[default]
+
+exten => echo,1,Answer()
+same => n,Echo()
+
+exten => bob,1,Dial(PJSIP/bob)
+
+exten => external_replaces,1,NoOp()
+same => n,Dial(PJSIP/asterisk2/${SIPREFERTOHDR})

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/extensions.conf
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/extensions.conf
------------------------------------------------------------------------------
    svn:keywords = 'Author Date Id Revision'

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/extensions.conf
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/pjsip.conf
URL: 
http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/pjsip.conf?view=auto&rev=6282
==============================================================================
--- 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/pjsip.conf
 (added)
+++ 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/pjsip.conf
 Wed Jan 14 15:15:42 2015
@@ -1,0 +1,23 @@
+[globals]
+type = global
+debug = yes
+
+[main-transport]
+type = transport
+protocol = udp
+bind = 127.0.0.1:5060
+
+[bob]
+type = endpoint
+context = default
+allow = ulaw
+aors = bob
+
+[bob]
+type = aor
+contact = sip:[email protected]:5062
+
+[asterisk2]
+type = endpoint
+allow = ulaw
+from_user = asterisk1

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/pjsip.conf
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/pjsip.conf
------------------------------------------------------------------------------
    svn:keywords = 'Author Date Id Revision'

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast1/pjsip.conf
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/extensions.conf
URL: 
http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/extensions.conf?view=auto&rev=6282
==============================================================================
--- 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/extensions.conf
 (added)
+++ 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/extensions.conf
 Wed Jan 14 15:15:42 2015
@@ -1,0 +1,6 @@
+[default]
+
+exten => echo,1,Dial(Local/echo2@default)
+
+exten => echo2,1,Answer()
+same => n,Echo()

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/extensions.conf
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/extensions.conf
------------------------------------------------------------------------------
    svn:keywords = 'Author Date Id Revision'

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/extensions.conf
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/pjsip.conf
URL: 
http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/pjsip.conf?view=auto&rev=6282
==============================================================================
--- 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/pjsip.conf
 (added)
+++ 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/pjsip.conf
 Wed Jan 14 15:15:42 2015
@@ -1,0 +1,23 @@
+[global]
+type = global
+debug = yes
+
+[main-transport]
+type = transport
+protocol = udp
+bind = 127.0.0.1:5061
+
+[bob]
+type = endpoint
+context = default
+allow = ulaw
+aors = bob
+
+[bob]
+type = aor
+max_contacts = 1
+
+[asterisk1]
+type = endpoint
+allow = ulaw
+from_user = asterisk2

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/pjsip.conf
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/pjsip.conf
------------------------------------------------------------------------------
    svn:keywords = 'Author Date Id Revision'

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/configs/ast2/pjsip.conf
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/test-config.yaml
URL: 
http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/test-config.yaml?view=auto&rev=6282
==============================================================================
--- 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/test-config.yaml
 (added)
+++ 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/test-config.yaml
 Wed Jan 14 15:15:42 2015
@@ -1,0 +1,89 @@
+testinfo:
+    summary: "Ensure that a nominal remote attended transfer works as 
expected."
+    description: |
+        "This test uses two Asterisk and a PJSUA instance to perform a remote 
attended
+        transfer. The PJSUA instance registers to Asterisk B, but Asterisk A 
has been
+        configured to be able to call the PJSUA instance directly.
+
+        Asterisk A originates a call. The first leg of the origination goes 
into the
+        dialplan and runs Echo(). The second leg of the origination places a 
call to
+        the PJSUA instance.
+
+        Once it is confirmed that Asterisk A and the PJSUA instance are 
bridged, the
+        PJSUA issues a call to Asterisk B. Asterisk B dials a local channel 
that runs
+        Echo().
+
+        Once it is confirmed that the PJSUA instance and Asterisk 2 are 
bridged, the
+        PJSUA instance performs an attended transfer. This results in the 
PJSUA instance
+        sending a REFER request to Asterisk A. Since the referenced dialog in 
the
+        REFER's Refer-To header is not in Asterisk A, Asterisk A must perform 
a remote
+        attended transfer.
+
+        A remote attended transfer, from the perspective of the Asterisk 
server that
+        is performing the transfer, actually appears to be a blind transfer, 
so a
+        BlindTransfer event is emitted during this transfer.
+
+        The end result should be that Asterisk A and Asterisk B are connected 
via SIP,
+        and the PJSUA instance has hung up.
+
+        This test kills two birds with one stone. Asterisk A is tested to 
ensure
+        that it properly handles a REFER that refers to a remote dialog. 
Asterisk B
+        is tested to ensure that it behaves correctly when receiving an INVITE 
with
+        replaces."
+
+test-modules:
+    add-test-to-search-path: True
+    test-object:
+        config-section: test-object-config
+        typename: test_case.TestCaseModule
+    modules:
+        -
+            config-section: pjsua-config
+            typename: 'pjsua_mod.PJsua'
+        -
+            config-section: ami-config
+            typename: 'ami.AMIEventModule'
+
+test-object-config:
+    connect-ami: True
+    asterisk-instances: 2
+
+pjsua-config:
+    callback_module: 'transfer'
+    callback_method: 'bob_registered'
+    transports:
+        -
+            name: 'local-ipv4'
+            bind: '127.0.0.1'
+            bindport: '5062'
+    accounts:
+        -
+            name: 'bob'
+            username: 'bob'
+            password: 'bob'
+            domain: '127.0.0.1:5061'
+
+ami-config:
+    -
+        type: 'headermatch'
+        id: '0'
+        conditions:
+            match:
+                Event: 'BlindTransfer'
+        requirements:
+            match:
+                TransfererChannel: 'PJSIP/bob-00000000'
+                TransfereeChannel: 'Local/echo@default-00000000;1'
+                Context: 'default'
+                Extension: 'external_replaces'
+
+properties:
+    minversion: '13.2.0'
+    dependencies:
+        - python: 'twisted'
+        - python: 'starpy'
+        - python: 'pjsua'
+        - asterisk: 'res_pjsip'
+        - asterisk: 'res_pjsip_session'
+        - asterisk: 'res_pjsip_refer'
+

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/test-config.yaml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/test-config.yaml
------------------------------------------------------------------------------
    svn:keywords = 'Author Date Id Revision'

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/test-config.yaml
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/transfer.py
URL: 
http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/transfer.py?view=auto&rev=6282
==============================================================================
--- 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/transfer.py
 (added)
+++ 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/transfer.py
 Wed Jan 14 15:15:42 2015
@@ -1,0 +1,148 @@
+"""
+Copyright (C) 2014, Digium, Inc.
+Mark Michelson <[email protected]>
+
+This program is free software, distributed under the terms of
+the GNU General Public License Version 2.
+"""
+
+import logging
+import pjsua as pj
+
+LOGGER = logging.getLogger(__name__)
+
+# Initial state. Bob has registered, but no calls have been placed yet.
+INITIAL = 0
+# Asterisk A has placed a call to Bob.
+BOB_CALLED = 1
+# Asterisk A and Bob are bridged, and now Bob has placed a call to Asterisk B.
+AST_B_CALLED = 2
+# Bob and Asterisk B are bridged, and Bob has now initiated the remote attended
+# transfer
+TRANSFER_INITIATED = 3
+# Asterisk A and Asterisk B are now bridged, and so the call is now being hung
+# up.
+HANGING_UP = 4
+
+class BobAccountCallback(pj.AccountCallback):
+    def __init__(self, account):
+        pj.AccountCallback.__init__(self, account)
+        self.incoming_call = None
+
+    def on_incoming_call(self, call):
+        LOGGER.info("Bob has incoming call from Asterisk A. Answering")
+        call.answer(200)
+        self.incoming_call = call
+
+
+class Transfer(object):
+    def __init__(self, test_object, bob):
+        super(Transfer, self).__init__()
+        self.ami_a = test_object.ami[0]
+
+        # BridgeEnter and BridgeLeave for Asterisk A are used to count the
+        # number of bridged channels. When two channels are bridged, then we
+        # know that a call is up and we can move on to the next state.
+        self.ami_a.registerEvent('BridgeEnter', self.ami_a_bridge_enter)
+        self.ami_a.registerEvent('BridgeLeave', self.ami_a_bridge_leave)
+        self.a_bridged_channels = 0
+
+        # BridgeEnter and BridgeLeave for Asterisk B are used for the same
+        # purposes as for Asterisk A.
+        self.ami_b = test_object.ami[1]
+        self.ami_b.registerEvent('BridgeEnter', self.ami_b_bridge_enter)
+        self.ami_b.registerEvent('BridgeLeave', self.ami_b_bridge_leave)
+        self.b_bridged_channels = 0
+
+        # Newchannel and Hangup events are used as a way of globally counting
+        # the number of channels on both Asterisk A and Asterisk B. We know the
+        # scenario can be stopped when the total number of channels reaches 0 
on
+        # a hangup.
+        self.ami_a.registerEvent('Newchannel', self.ami_new_channel)
+        self.ami_b.registerEvent('Newchannel', self.ami_new_channel)
+        self.ami_a.registerEvent('Hangup', self.ami_hangup)
+        self.ami_b.registerEvent('Hangup', self.ami_hangup)
+        self.channels = 0
+
+        self.bob = bob
+        self.bob_callback = BobAccountCallback(self.bob)
+        self.bob.set_callback(self.bob_callback)
+        self.call_from_bob = None
+
+        self.test_object = test_object
+        self.state = INITIAL
+
+    def ami_a_bridge_enter(self, ami, event):
+        LOGGER.info("Asterisk A channel {0} entered "
+                    "bridge".format(event['channel']))
+
+        if self.state == BOB_CALLED:
+            self.a_bridged_channels += 1
+            if self.a_bridged_channels == 2:
+                LOGGER.info("Initial bridge complete, placing call from Bob to 
B")
+                self.call_from_bob = self.bob.make_call(
+                        'sip:[email protected]:5061', pj.CallCallback())
+                self.state = AST_B_CALLED
+        elif self.state == TRANSFER_INITIATED:
+            self.a_bridged_channels += 1
+            if self.a_bridged_channels == 2:
+                LOGGER.info("Second bridge complete, Hanging up call")
+                hangup_msg = {
+                    'Action': 'Hangup',
+                    'Channel': 'Local/echo@default-00000000;2',
+                }
+                self.ami_a.sendMessage(hangup_msg)
+                self.state = HANGING_UP
+        else:
+            LOGGER.error("Received BridgeEnter event during unexpected state "
+                         "{0}".format(self.state))
+
+    def ami_a_bridge_leave(self, ami, event):
+        LOGGER.info("Asterisk A channel {0} left "
+                    "bridge".format(event['channel']))
+        self.a_bridged_channels -= 1
+
+    def ami_b_bridge_enter(self, ami, event):
+        LOGGER.info("Asterisk B channel {0} entered "
+                    "bridge".format(event['channel']))
+
+        if self.state == AST_B_CALLED:
+            self.b_bridged_channels += 1
+            if self.b_bridged_channels == 2:
+                LOGGER.info("Initial bridge complete. Can now perform 
transfer")
+                
self.bob_callback.incoming_call.transfer_to_call(self.call_from_bob)
+                self.state = TRANSFER_INITIATED
+
+    def ami_b_bridge_leave(self, ami, event):
+        LOGGER.info("Asterisk B channel {0} left "
+                    "bridge".format(event['channel']))
+        self.b_bridged_channels -= 1
+
+    def ami_new_channel(self, ami, event):
+        self.channels += 1
+
+    def ami_hangup(self, ami, event):
+        self.channels -= 1
+
+        if self.channels == 0:
+            LOGGER.info("All channels hung up! Ending Test")
+            self.test_object.set_passed(True)
+            self.test_object.stop_reactor()
+
+    def call_bob(self):
+        originate_msg = {
+            'Action': 'Originate',
+            'Channel': 'Local/echo@default',
+            'Exten': 'bob',
+            'Context': 'default',
+            'Priority': '1',
+        }
+        self.ami_a.sendMessage(originate_msg)
+        LOGGER.info("Placed call from Asterisk A to Bob")
+        self.state = BOB_CALLED
+
+
+def bob_registered(test_object, accounts):
+    transfer = Transfer(test_object, accounts.get('bob').account)
+    transfer.call_bob()
+

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/transfer.py
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/transfer.py
------------------------------------------------------------------------------
    svn:executable = *

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/transfer.py
------------------------------------------------------------------------------
    svn:keywords = 'Author Date Id Revision'

Propchange: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/callee_remote/transfer.py
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/tests.yaml
URL: 
http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/tests.yaml?view=diff&rev=6282&r1=6281&r2=6282
==============================================================================
--- 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/tests.yaml
 (original)
+++ 
asterisk/trunk/tests/channels/pjsip/transfers/attended_transfer/nominal/tests.yaml
 Wed Jan 14 15:15:42 2015
@@ -2,4 +2,4 @@
 tests:
     - test: 'caller_local'
     - test: 'callee_local'
-
+    - test: 'callee_remote'


-- 
_____________________________________________________________________
-- Bandwidth and Colocation Provided by http://www.api-digital.com --

svn-commits mailing list
To UNSUBSCRIBE or update options visit:
   http://lists.digium.com/mailman/listinfo/svn-commits

Reply via email to