[asterisk-dev] Change in testsuite[master]: sip_attended_transfer now supports pre-12 Asterisk versions.

Mark Michelson (Code Review) asteriskteam at digium.com
Fri Apr 3 15:36:50 CDT 2015


Mark Michelson has uploaded a new change for review.

  https://gerrit.asterisk.org/29

Change subject: sip_attended_transfer now supports pre-12 Asterisk versions.
......................................................................

sip_attended_transfer now supports pre-12 Asterisk versions.

The sip_attended transfer test was recently rewritten to prevent it from
bouncing during automatic test runs. The rewrite attempted to break into
two tests in an attempt to separate the logic of different versions from
one another.

Ashley pointed out on my original Asterisk 11 version of the patch that
there are only small difference between the Asterisk 11 and 12 versions
of the test, resulting in a lot of repeated boilerplate code that could
otherwise be avoided.

This change alters the 12+ specific test by separating the bridge logic
for different versions into their own classes. I have verified that the
test passes using both Asterisk 11 and Asterisk 13.

Change-Id: I958c52cebb94f9cfc8dc8ed81311ae62efb2679d
---
M tests/channels/SIP/sip_attended_transfer/attended_transfer.py
M tests/channels/SIP/sip_attended_transfer/test-config.yaml
2 files changed, 125 insertions(+), 45 deletions(-)


  git pull ssh://gerrit.asterisk.org:29418/testsuite refs/changes/29/29/1

diff --git a/tests/channels/SIP/sip_attended_transfer/attended_transfer.py b/tests/channels/SIP/sip_attended_transfer/attended_transfer.py
index cb133f3..ef9f314 100644
--- a/tests/channels/SIP/sip_attended_transfer/attended_transfer.py
+++ b/tests/channels/SIP/sip_attended_transfer/attended_transfer.py
@@ -8,7 +8,11 @@
 
 import logging
 import pjsua as pj
+import sys
 
+sys.path.append('lib/python/asterisk')
+
+from version import AsteriskVersion
 from twisted.internet import reactor
 
 LOGGER = logging.getLogger(__name__)
@@ -52,8 +56,8 @@
             reactor.callFromThread(self.on_answered)
 
 
-class BridgeState(object):
-    '''Object for tracking state of a bridge
+class BridgeTwelve(object):
+    '''Object for tracking attributes of an Asterisk 12+ bridge
 
     The main data the test cares about is the bridge's unique id and whether two
     channels have been bridged together by the bridge.
@@ -61,6 +65,118 @@
     def __init__(self):
         self.unique_id = None
         self.bridged = False
+
+
+class BridgeStateTwelve(object):
+    '''Tracker of Bridge State for Asterisk 12+
+
+    Since Asterisk 12+ has the concept of Bridge objects, this tracks the
+    bridges by detecting when they are created. Once bridges are created, we
+    determine that channels are bridged when BridgeEnter events indicate that
+    two channels are present.
+    '''
+    def __init__(self, test_object, controller, ami):
+        self.test_object = test_object
+        self.controller = controller
+        self.ami = ami
+        self.bridge1 = BridgeTwelve()
+        self.bridge2 = BridgeTwelve()
+
+        self.ami.registerEvent('BridgeCreate', self.bridge_create)
+        self.ami.registerEvent('BridgeEnter', self.bridge_enter)
+
+    def bridge_create(self, ami, event):
+        if not self.bridge1.unique_id:
+            self.bridge1.unique_id = event.get('bridgeuniqueid')
+        elif not self.bridge2.unique_id:
+            self.bridge2.unique_id = event.get('bridgeuniqueid')
+        else:
+            LOGGER.error("Unexpected third bridge created")
+            self.test_object.set_passed(False)
+            self.test_object.stop_reactor()
+
+    def bridge_enter(self, ami, event):
+        if (event.get('bridgeuniqueid') == self.bridge1.unique_id and
+                event.get('bridgenumchannels') == '2'):
+            self.bridge1.bridged = True
+            if self.controller.state == BOB_CALLED:
+                self.controller.call_carol()
+            elif self.controller.state == TRANSFERRED:
+                self.controller.hangup_calls()
+            else:
+                LOGGER.error("Unexpected BridgeEnter event")
+                self.test_object.set_passed(False)
+                self.test_object.stop_reactor()
+        elif (event.get('bridgeuniqueid') == self.bridge2.unique_id and
+              event.get('bridgenumchannels') == '2'):
+            self.bridge2.bridged = True
+            if self.controller.state == CAROL_CALLED:
+                self.controller.transfer_call()
+            elif self.controller.state == TRANSFERRED:
+                self.controller.hangup_calls()
+            else:
+                LOGGER.error("Unexpected BridgeEnter event")
+                self.test_object.set_passed(False)
+                self.test_object.stop_reactor()
+
+    def bridge1_bridged(self):
+        return self.bridge1.bridged
+
+    def bridge2_bridged(self):
+        return self.bridge2.bridged
+
+
+class BridgeStateEleven(object):
+    '''Tracker of bridge state for Asterisk 11-
+
+    Since in Asterisk versions prior to 12, there are no bridge objects, the
+    only way we can track the state of bridges in Asterisk is via Bridge events
+    and our own channel count. We count unique bridges by using the "channel2"
+    header in Bridge events from Asterisk.
+    '''
+    def __init__(self, test_object, controller, ami):
+        self.test_object = test_object
+        self.controller = controller
+        self.ami = ami
+        self.chans = []
+        self.final_bridge = 0
+
+        self.ami.registerEvent('Bridge', self.bridge)
+        self.ami.registerEvent('VarSet', self.bridge_peer)
+
+    def bridge(self, ami, event):
+        if event['channel2'] in self.chans:
+            return
+
+        self.chans.append(event['channel2'])
+        numchans = len(self.chans)
+        if numchans == 1:
+            self.controller.call_carol()
+        elif numchans == 2:
+            self.controller.transfer_call()
+
+    def bridge_peer(self, ami, event):
+        if event['variable'] != "BRIDGEPEER" or len(self.chans) < 2:
+            return
+
+        LOGGER.info("Inspecting BRIDGEPEER VarSet")
+
+        # we should get 2 bridgepeers with swapped channel and value headers
+        # indicating the bridged channels
+        if self.chans[:2] == [event['channel'], event['value']] or\
+            self.chans[:2] == [event['value'], event['channel']]:
+            LOGGER.info("Got expected VarSet")
+            self.final_bridge += 1
+            if self.final_bridge == 2:
+                LOGGER.info("Transfer successful!")
+                # success!
+                self.controller.hangup_calls()
+
+    def bridge1_bridged(self):
+        return len(self.chans) == 1
+
+    def bridge2_bridged(self):
+        return len(self.chans) == 2
 
 
 class Transfer(object):
@@ -74,13 +190,11 @@
     def __init__(self, test_object, accounts):
         super(Transfer, self).__init__()
         self.ami = test_object.ami[0]
-        self.ami.registerEvent('BridgeCreate', self.bridge_create)
-        self.ami.registerEvent('BridgeEnter', self.bridge_enter)
 
-        # bridge1 bridges Alice and Bob
-        self.bridge1 = BridgeState()
-        # bridge2 bridges Alice and Carol
-        self.bridge2 = BridgeState()
+        if AsteriskVersion() < AsteriskVersion('12'):
+            self.bridge_state = BridgeStateEleven(test_object, self, self.ami)
+        else:
+            self.bridge_state = BridgeStateTwelve(test_object, self, self.ami)
 
         self.bob_call_answered = False
         self.carol_call_answered = False
@@ -98,40 +212,6 @@
         self.test_object = test_object
         self.state = INIT
 
-    def bridge_create(self, ami, event):
-        if not self.bridge1.unique_id:
-            self.bridge1.unique_id = event.get('bridgeuniqueid')
-        elif not self.bridge2.unique_id:
-            self.bridge2.unique_id = event.get('bridgeuniqueid')
-        else:
-            LOGGER.error("Unexpected third bridge created")
-            self.test_object.set_passed(False)
-            self.test_object.stop_reactor()
-
-    def bridge_enter(self, ami, event):
-        if (event.get('bridgeuniqueid') == self.bridge1.unique_id and
-                event.get('bridgenumchannels') == '2'):
-            self.bridge1.bridged = True
-            if self.state == BOB_CALLED:
-                self.call_carol()
-            elif self.state == TRANSFERRED:
-                self.hangup_calls()
-            else:
-                LOGGER.error("Unexpected BridgeEnter event")
-                self.test_object.set_passed(False)
-                self.test_object.stop_reactor()
-        elif (event.get('bridgeuniqueid') == self.bridge2.unique_id and
-                event.get('bridgenumchannels') == '2'):
-            self.bridge2.bridged = True
-            if self.state == CAROL_CALLED:
-                self.transfer_call()
-            elif self.state == TRANSFERRED:
-                self.hangup_calls()
-            else:
-                LOGGER.error("Unexpected BridgeEnter event")
-                self.test_object.set_passed(False)
-                self.test_object.stop_reactor()
-
     def bob_call_confirmed(self):
         self.bob_call_answered = True
         self.call_carol()
@@ -146,13 +226,13 @@
         self.state = BOB_CALLED
 
     def call_carol(self):
-        if self.bridge1.bridged and self.bob_call_answered:
+        if self.bridge_state.bridge1_bridged() and self.bob_call_answered:
             self.call_to_carol = self.alice.make_call('sip:carol at 127.0.0.1',
                     CallCallback(None, self.carol_call_confirmed))
             self.state = CAROL_CALLED
 
     def transfer_call(self):
-        if self.bridge2.bridged and self.carol_call_answered:
+        if self.bridge_state.bridge2_bridged and self.carol_call_answered:
             self.call_to_bob.transfer_to_call(self.call_to_carol)
             self.state = TRANSFERRED
 
diff --git a/tests/channels/SIP/sip_attended_transfer/test-config.yaml b/tests/channels/SIP/sip_attended_transfer/test-config.yaml
index 7fe5c60..5b8e3b2 100644
--- a/tests/channels/SIP/sip_attended_transfer/test-config.yaml
+++ b/tests/channels/SIP/sip_attended_transfer/test-config.yaml
@@ -47,7 +47,7 @@
             transport: 'local-ipv4'
 
 properties:
-    minversion: '12.0.0'
+    minversion: '1.8.0'
     dependencies:
         - python : 'twisted'
         - python : 'starpy'

-- 
To view, visit https://gerrit.asterisk.org/29
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I958c52cebb94f9cfc8dc8ed81311ae62efb2679d
Gerrit-PatchSet: 1
Gerrit-Project: testsuite
Gerrit-Branch: master
Gerrit-Owner: Mark Michelson <mmichelson at digium.com>



More information about the asterisk-dev mailing list