<p>Jenkins2 <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/5823">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Joshua Colp: Looks good to me, approved
  Jenkins2: Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Test receiving an early BYE during an attended transfer<br><br>Asterisk used to fail the transfer and drop the call if an early BYE (sometime<br>just after the 202 accepted, but before the Notify 200 OK frag) was received.<br>Added a test that makes sure the transfer does not fail when an early BYE is<br>received.<br><br>This patch modified the testsuite's pjsua phones wrapper to allow configuring<br>of when to send the transferer's BYE during the transfer process. A new option,<br>'hangup-reason', has been added that specifies when to send the BYE. Allowed<br>values are:<br><br>  accepted - Sent right after the refer is accepted<br>  trying - Sent right after receiving a sip frag 100 Trying<br>  ok - Sent right after receiving a sip frag 200 OK<br>  final - Sent upon receiving the final message<br><br>A test was also added that sends a BYE right after the REFER is accepted. As<br>noted in test-config.yaml this test is a direct copy of the 'same_stasis_app'<br>test except for when the BYE is sent.<br><br>ASTERISK-27053<br><br>Change-Id: Ifbf1d6e8f91dfc00128a2ccd7eaff6402d170650<br>---<br>M lib/python/asterisk/phones.py<br>M tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app/test-config.yaml<br>A tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app_accepted/configs/ast1/extensions.conf<br>A tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app_accepted/configs/ast1/pjsip.conf<br>A tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app_accepted/test-config.yaml<br>M tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/tests.yaml<br>6 files changed, 618 insertions(+), 17 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/lib/python/asterisk/phones.py b/lib/python/asterisk/phones.py<br>index c4822eb..6a96b38 100755<br>--- a/lib/python/asterisk/phones.py<br>+++ b/lib/python/asterisk/phones.py<br>@@ -116,6 +116,7 @@<br> <br>     def __init__(self, controller, account_config):<br>         """Constructor"""<br>+        self.config = account_config<br>         self.name = account_config['name']<br>         self.account = controller.pj_accounts[self.name].account<br>         self.pj_lib = controller.pj_accounts[self.name].pj_lib<br>@@ -137,7 +138,7 @@<br>         call = None<br>         try:<br>             LOGGER.info("'%s' is calling '%s'" % (self.name, uri))<br>-            call_cb = PhoneCallCallback()<br>+            call_cb = PhoneCallCallback(config=self.config)<br>             call = self.account.make_call(uri, cb=call_cb)<br>             self.calls.append(call)<br>         except pj.Error as err:<br>@@ -259,10 +260,21 @@<br> <br> <br> class PhoneCallCallback(pj.CallCallback):<br>-    """Derived callback class for calls."""<br>+    """Derived callback class for calls.<br> <br>-    def __init__(self, call=None):<br>+    configuration:<br>+        hangup-reason - Specifies when to hangup during a transfer. The<br>+            following values are allowed:<br>+                accepted - Sent right after the refer is accepted<br>+                trying - Sent right after receiving a sip frag 100 Trying<br>+                ok - Sent right after receiving a sip frag 200 OK<br>+                final - Sent upon receiving the final message<br>+    """<br>+<br>+    def __init__(self, call=None, config=None):<br>         pj.CallCallback.__init__(self, call)<br>+        self.hangup_reason = (config.get('hangup-reason', 'ok')<br>+                              if config else 'ok').lower()<br>         self.controller = PjsuaPhoneController.get_instance()<br>         self.phone = None<br>         if call is not None:<br>@@ -300,30 +312,30 @@<br> <br>     def on_transfer_status(self, code, reason, final, cont):<br>         """Callback for the status of a previous call transfer request."""<br>+<br>         LOGGER.debug(fmt_call_info(self.call.info()))<br>         status_format = "\n=== Transfer Status ==="<br>         status_format += "\nCode: '%s'"<br>         status_format += "\nReason: '%s'"<br>         status_format += "\nFinal Notification: '%s'\n"<br>         LOGGER.debug(status_format % (code, reason, final))<br>-        if final != 1:<br>-            return cont<br> <br>-        LOGGER.debug("Call uri: '%s'; remote uri: '%s'" %<br>-                     (self.call.info().uri, self.call.info().remote_uri))<br>         if code == 200 and reason == "OK" and cont == 0:<br>             LOGGER.info("Transfer target answered the call.")<br>-        else:<br>-            LOGGER.warn("Transfer failed!")<br> <br>-        self.phone.remove_call_op_tracking(self.call, operation='transfer')<br>+        if (reason.lower() == self.hangup_reason or<br>+                (final and self.hangup_reason == 'final')):<br>+            LOGGER.debug("Call uri: '%s'; remote uri: '%s'" %<br>+                         (self.call.info().uri, self.call.info().remote_uri))<br> <br>-        try:<br>-            LOGGER.info("Hanging up '%s'" % self.call)<br>-            self.call.hangup(code=200, reason="Q.850;cause=16")<br>-        except pj.Error as err:<br>-            LOGGER.warn("Failed to hangup the call!")<br>-            LOGGER.warn("Exception: %s" % str(err))<br>+            self.phone.remove_call_op_tracking(self.call, operation='transfer')<br>+<br>+            try:<br>+                LOGGER.info("Hanging up '%s'" % self.call)<br>+                self.call.hangup(reason="Q.850;cause=16")<br>+            except pj.Error as err:<br>+                LOGGER.warn("Failed to hangup the call!")<br>+                LOGGER.warn("Exception: %s" % str(err))<br> <br>         return cont<br> <br>diff --git a/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app/test-config.yaml b/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app/test-config.yaml<br>index cdb3ed0..3ecc0f2 100644<br>--- a/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app/test-config.yaml<br>+++ b/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app/test-config.yaml<br>@@ -489,7 +489,7 @@<br>             uri: 'bridges/test_bridge_b'<br> <br> properties:<br>-    minversion: '13.5.0'<br>+    minversion: ['13.17.0', '14.6.0']<br>     dependencies:<br>         - python : autobahn.websocket<br>         - python : requests<br>diff --git a/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app_accepted/configs/ast1/extensions.conf b/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app_accepted/configs/ast1/extensions.conf<br>new file mode 100644<br>index 0000000..7e34248<br>--- /dev/null<br>+++ b/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app_accepted/configs/ast1/extensions.conf<br>@@ -0,0 +1,22 @@<br>+[default]<br>+<br>+exten => dummy,1,NoOp()<br>+        same => n,Answer()<br>+        same => n,Stasis(testsuite,dummy)<br>+ same => n,Hangup()<br>+<br>+exten => echo,1,NoOp()<br>+ same => n,Answer()<br>+        same => n,Echo()<br>+  same => n,Hangup()<br>+<br>+exten => stasis_one,1,NoOp()<br>+   same => n,Answer()<br>+        same => n,Stasis(testsuite,one)<br>+   same => n,Hangup<br>+<br>+exten => stasis_two,1,NoOp()<br>+     same => n,Answer()<br>+        same => n,Stasis(testsuite,two)<br>+   same => n,Hangup<br>+<br>diff --git a/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app_accepted/configs/ast1/pjsip.conf b/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app_accepted/configs/ast1/pjsip.conf<br>new file mode 100644<br>index 0000000..ffac34c<br>--- /dev/null<br>+++ b/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app_accepted/configs/ast1/pjsip.conf<br>@@ -0,0 +1,54 @@<br>+[global]<br>+type=global<br>+debug=yes<br>+<br>+[system]<br>+type=system<br>+<br>+[local]<br>+type=transport<br>+protocol=udp<br>+bind=127.0.0.1:5060<br>+<br>+[alice]<br>+type=endpoint<br>+context=default<br>+disallow=all<br>+allow=ulaw<br>+direct_media=no<br>+media_address=127.0.0.1<br>+aors=alice<br>+<br>+[alice]<br>+type=aor<br>+max_contacts=1<br>+contact=sip:alice@127.0.0.1:5061\;transport=udp<br>+<br>+[bob]<br>+type=endpoint<br>+context=default<br>+disallow=all<br>+allow=ulaw<br>+direct_media=no<br>+media_address=127.0.0.1<br>+aors=bob<br>+<br>+[bob]<br>+type=aor<br>+max_contacts=1<br>+contact=sip:bob@127.0.0.1:5062\;transport=udp<br>+<br>+[carol]<br>+type=endpoint<br>+context=default<br>+disallow=all<br>+allow=ulaw<br>+direct_media=no<br>+media_address=127.0.0.1<br>+aors=carol<br>+<br>+[carol]<br>+type=aor<br>+max_contacts=1<br>+contact=sip:carol@127.0.0.1:5063\;transport=udp<br>+<br>diff --git a/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app_accepted/test-config.yaml b/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app_accepted/test-config.yaml<br>new file mode 100644<br>index 0000000..5663898<br>--- /dev/null<br>+++ b/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/same_stasis_app_accepted/test-config.yaml<br>@@ -0,0 +1,512 @@<br>+testinfo:<br>+    summary: |<br>+        "Transfer (attended) Stasis bridge to Stasis bridge in same Stasis app"<br>+    description: |<br>+        "NOTE - The only difference between this test and the same_stasis_app<br>+         test is that the transferer hangs up immediately after the REFER has<br>+         been accepted instead of waiting until receiving the NOTIFY with the<br>+         200 OK frag. This allows the test to make sure the transfer completes<br>+         even when Asterisk receives an early BYE.<br>+<br>+         Upon the kick off local channel entering into the Stasis(testsuite)<br>+         app, a call is made from the 'alice' PJSUA account that is put into<br>+         Stasis(testsuite). The Stasis bridge 'test_bridge_a' is created and<br>+         alice is added to it. A channel is originated to the 'bob' PJSUA<br>+         account and put into the same Stasis(testsuite) app and bridge with<br>+         alice. Alice begins an attended transfer by making another call. The<br>+         second alice channel is put into the same Stasis(testsuite) app, the<br>+         Stasis bridge 'test_bridge_b' is created, and the second alice channel<br>+         is added to Stasis bridge. A channel is then originated to the 'carol'<br>+         PJSUA account and put into the same Stasis(testsuite) app and bridge<br>+         with the second alice channel.<br>+<br>+         Alice then completes the attended transfer essentially transferring<br>+         the Stasis bridge to the other Stasis bridge within the same Stasis<br>+         app. Asterisk does this by creating a Local channel where each half is<br>+         swapped in place of the two alice channels. After the transfer is<br>+         successful with a local replacement channel half in the Stasis bridge<br>+         with bob and another in the Stasis bridge with carol, bob is hung up.<br>+         Carol is then hung up and so is the local replacement channel half<br>+         that was in the Stasis bridge with bob. This causes the other local<br>+         replacement channel half that was in the Stasis bridge with carol to<br>+         be hung up and triggers the hang up of the kick off local channel and<br>+         the destruction of the stasis bridges.<br>+<br>+         This test verifies that a Stasis bridge can be transferred (attended)<br>+         to a Stasis bridge in the same Stasis app. It also verifies that the<br>+         StasisStart & StasisEnd events occur for the alice(both), bob, carol,<br>+         and local replacement channels."<br>+<br>+test-modules:<br>+    test-object:<br>+        config-section: test-object-config<br>+        typename: 'ari.AriOriginateTestObject'<br>+    modules:<br>+        -<br>+            config-section: 'pjsua-config'<br>+            typename: 'phones.PjsuaPhoneController'<br>+        -<br>+            config-section: pluggable-config<br>+            typename: 'pluggable_modules.EventActionModule'<br>+<br>+test-object-config:<br>+    apps: testsuite<br>+    test-iterations:<br>+        -<br>+            channelId: 'dummy'<br>+            endpoint: 'Local/dummy@default'<br>+            context: 'default'<br>+            extension: 'echo'<br>+            priority: '1'<br>+<br>+pjsua-config:<br>+    transports:<br>+        -<br>+            name: 'local-ipv4-1'<br>+            bind: '127.0.0.1'<br>+            bindport: '5061'<br>+        -<br>+            name: 'local-ipv4-2'<br>+            bind: '127.0.0.1'<br>+            bindport: '5062'<br>+        -<br>+            name: 'local-ipv4-3'<br>+            bind: '127.0.0.1'<br>+            bindport: '5063'<br>+    accounts:<br>+        -<br>+            name: 'alice'<br>+            username: 'alice'<br>+            domain: '127.0.0.1'<br>+            transport: 'local-ipv4-1'<br>+            hangup-reason: 'accepted' # Hang up after REFER, but before NOTIFY<br>+        -<br>+            name: 'bob'<br>+            username: 'bob'<br>+            domain: '127.0.0.1'<br>+            transport: 'local-ipv4-2'<br>+        -<br>+            name: 'carol'<br>+            username: 'carol'<br>+            domain: '127.0.0.1'<br>+            transport: 'local-ipv4-3'<br>+<br>+pluggable-config:<br>+    # Upon kickoff channel entering Stasis app: create a bridge, don't add<br>+    # kickoff channel to bridge, instruct alice to place call to<br>+    # Stasis(testsuite,one).<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: StasisStart<br>+                application: 'testsuite'<br>+                args: ['dummy']<br>+                channel:<br>+                    id: 'dummy;2'<br>+            count: 1<br>+        pjsua_phone:<br>+            action: 'call'<br>+            pjsua_account: 'alice'<br>+            call_uri: 'sip:stasis_one@127.0.0.1'<br>+    # Upon alice entering the Stasis app: create the stasis bridge<br>+    # 'test_bridge_a', add alice's first channel to the Stasis bridge, and<br>+    # originate a call to bob.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: StasisStart<br>+                application: 'testsuite'<br>+                args: ['one']<br>+                channel:<br>+                    name: 'PJSIP/alice-.*'<br>+            count: 1<br>+        ari-requests:<br>+            -<br>+                method: 'post'<br>+                uri: 'bridges/test_bridge_a'<br>+            -<br>+                method: 'post'<br>+                uri: 'bridges/test_bridge_a/addChannel'<br>+                params:<br>+                    channel: '{channel.id}'<br>+            -<br>+                method: 'post'<br>+                uri: 'channels/bob'<br>+                params:<br>+                    endpoint: 'PJSIP/bob'<br>+                    context: 'default'<br>+                    extension: 'stasis_one'<br>+                    priority: '1'<br>+    # Ensure alice's first channel enters the Stasis bridge 'test_bridge_a'.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: ChannelEnteredBridge<br>+                application: 'testsuite'<br>+                bridge:<br>+                    id: 'test_bridge_a'<br>+                channel:<br>+                    name: 'PJSIP/alice-.*'<br>+            count: 1<br>+    # Ensure bob enters the Stasis app. Then add bob to the Stasis bridge<br>+    # with alice's first channel.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: StasisStart<br>+                application: 'testsuite'<br>+                args: ['one']<br>+                channel:<br>+                    name: 'PJSIP/bob-.*'<br>+            count: 1<br>+        ari-requests:<br>+            method: 'post'<br>+            uri: 'bridges/test_bridge_a/addChannel'<br>+            params:<br>+                channel: '{channel.id}'<br>+    # Ensure bob's channel enters the Stasis bridge with alice's first<br>+    # channel. Then instruct alice to place another call to<br>+    # Stasis(testsuite,two).<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: ChannelEnteredBridge<br>+                application: 'testsuite'<br>+                bridge:<br>+                    id: 'test_bridge_a'<br>+                channel:<br>+                    name: 'PJSIP/bob-.*'<br>+            count: 1<br>+        pjsua_phone:<br>+            action: 'call'<br>+            pjsua_account: 'alice'<br>+            call_uri: 'sip:stasis_two@127.0.0.1'<br>+    # Upon alice's second channel entering the Stasis app: create the stasis<br>+    # bridge 'test_bridge_b', add alice's second channel to the Stasis bridge,<br>+    # and originate a call to carol.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: StasisStart<br>+                application: 'testsuite'<br>+                args: ['two']<br>+                channel:<br>+                    name: 'PJSIP/alice-.*'<br>+            count: 1<br>+        ari-requests:<br>+            -<br>+                method: 'post'<br>+                uri: 'bridges/test_bridge_b'<br>+            -<br>+                method: 'post'<br>+                uri: 'bridges/test_bridge_b/addChannel'<br>+                params:<br>+                    channel: '{channel.id}'<br>+            -<br>+                method: 'post'<br>+                uri: 'channels/carol'<br>+                params:<br>+                    endpoint: 'PJSIP/carol'<br>+                    context: 'default'<br>+                    extension: 'stasis_two'<br>+                    priority: '1'<br>+    # Ensure alice's second channel enters the Stasis bridge 'test_bridge_b'.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: ChannelEnteredBridge<br>+                application: 'testsuite'<br>+                bridge:<br>+                    id: 'test_bridge_b'<br>+                channel:<br>+                    name: 'PJSIP/alice-.*'<br>+            count: 1<br>+    # Ensure carol enters the Stasis app. Then add carol to the Stasis bridge<br>+    # with alice's second channel.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: StasisStart<br>+                application: 'testsuite'<br>+                args: ['two']<br>+                channel:<br>+                    name: 'PJSIP/carol-.*'<br>+            count: 1<br>+        ari-requests:<br>+            method: 'post'<br>+            uri: 'bridges/test_bridge_b/addChannel'<br>+            params:<br>+                channel: '{channel.id}'<br>+    # Ensure carol's channel enters the Stasis bridge with alice's second<br>+    # channel. Then instruct alice to perform an attended transfer. This is to<br>+    # transfer the remote side of the first channel which is a Stasis bridge to<br>+    # the remote side of the second channel which is also a Stasis bridge.<br>+    # Essentially bob will be in the Stasis bridge 'test_bridge_a', carol will<br>+    # be in the Stasis bridge 'test_bridge_b', and the halves of a local<br>+    # channel will be in each thus linking the two Stasis bridges.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: ChannelEnteredBridge<br>+                application: 'testsuite'<br>+                bridge:<br>+                    id: 'test_bridge_b'<br>+                channel:<br>+                    name: 'PJSIP/carol-.*'<br>+            count: 1<br>+        pjsua_phone:<br>+            action: 'transfer'<br>+            pjsua_account: 'alice'<br>+            transfer_type: 'attended'<br>+    # Ensure the attended transfer occurs with the proper info.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: BridgeAttendedTransfer<br>+                application: 'testsuite'<br>+                transferer_first_leg:<br>+                    name: 'PJSIP/alice-.*'<br>+                transferer_first_leg_bridge:<br>+                    id: 'test_bridge_a'<br>+                    bridge_class: 'stasis'<br>+                transferer_second_leg:<br>+                    name: 'PJSIP/alice-.*'<br>+                transferer_second_leg_bridge:<br>+                    id: 'test_bridge_b'<br>+                    bridge_class: 'stasis'<br>+                transferee:<br>+                    name: 'PJSIP/bob-.*'<br>+                transfer_target:<br>+                    id: 'carol'<br>+                destination_type: 'link'<br>+                destination_link_first_leg:<br>+                    name: 'Local/_attended@transfer-.*;1'<br>+                destination_link_second_leg:<br>+                    name: 'Local/_attended@transfer-.*;2'<br>+                result: 'Success'<br>+            count: 1<br>+    # Ensure the local channel half for the transfer that is replacing alice's<br>+    # first channel enters the Stasis(testsuite) application.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: StasisStart<br>+                application: 'testsuite'<br>+                args: []<br>+                channel:<br>+                    name: 'Local/_attended@transfer-.*;1'<br>+                replace_channel:<br>+                    name: 'PJSIP/alice-.*'<br>+            count: 1<br>+    # Ensure alice's first channel leaves the Stasis bridge.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: ChannelLeftBridge<br>+                application: 'testsuite'<br>+                bridge:<br>+                    id: 'test_bridge_a'<br>+                channel:<br>+                    name: 'PJSIP/alice-.*'<br>+            count: 1<br>+    # Ensure the local channel half for the transfer that is replacing alice's<br>+    # first channel enters the Stasis bridge 'test_bridge_a'.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: ChannelEnteredBridge<br>+                application: 'testsuite'<br>+                bridge:<br>+                    id: 'test_bridge_a'<br>+                channel:<br>+                    name: 'Local/_attended@transfer-.*;1'<br>+            count: 1<br>+    # Ensure alice's first channel exits the Stasis app.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: StasisEnd<br>+                application: 'testsuite'<br>+                channel:<br>+                    name: 'PJSIP/alice-.*'<br>+                    dialplan:<br>+                        exten: 'stasis_one'<br>+            count: 1<br>+    # Ensure the local channel half for the transfer that is replacing alice's<br>+    # second channel enters the Stasis(testsuite) application.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: StasisStart<br>+                application: 'testsuite'<br>+                args: []<br>+                channel:<br>+                    name: 'Local/_attended@transfer-.*;2'<br>+                replace_channel:<br>+                    name: 'PJSIP/alice-.*'<br>+            count: 1<br>+    # Ensure alice's second channel leaves the Stasis bridge.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: ChannelLeftBridge<br>+                application: 'testsuite'<br>+                bridge:<br>+                    id: 'test_bridge_b'<br>+                channel:<br>+                    name: 'PJSIP/alice-.*'<br>+            count: 1<br>+    # Ensure the local channel half for the transfer that is replacing alice's<br>+    # second channel enters the Stasis bridge 'test_bridge_b'.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: ChannelEnteredBridge<br>+                application: 'testsuite'<br>+                bridge:<br>+                    id: 'test_bridge_b'<br>+                channel:<br>+                    name: 'Local/_attended@transfer-.*;2'<br>+            count: 1<br>+    # Ensure alice's second channel exits the Stasis app. Then hang up bob.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: StasisEnd<br>+                application: 'testsuite'<br>+                channel:<br>+                    name: 'PJSIP/alice-.*'<br>+                    dialplan:<br>+                        exten: 'stasis_two'<br>+            count: 1<br>+        ami-actions:<br>+            action:<br>+               action: 'Hangup'<br>+               channel: '/^PJSIP/bob-.*$/'<br>+    # Upon hanging up bob, ensure bob leaves the Stasis bridge.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: ChannelLeftBridge<br>+                application: 'testsuite'<br>+                bridge:<br>+                    id: 'test_bridge_a'<br>+                channel:<br>+                    name: 'PJSIP/bob-.*'<br>+            count: 1<br>+    # Ensure bob exits the Stasis app. Then hang up carol.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: StasisEnd<br>+                application: 'testsuite'<br>+                channel:<br>+                    name: 'PJSIP/bob-.*'<br>+                    dialplan:<br>+                        exten: 'stasis_one'<br>+            count: 1<br>+        ami-actions:<br>+            action:<br>+               action: 'Hangup'<br>+               channel: 'carol'<br>+    # Ensure carol leaves the Stasis bridge.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: ChannelLeftBridge<br>+                application: 'testsuite'<br>+                bridge:<br>+                    id: 'test_bridge_b'<br>+                channel:<br>+                    name: 'PJSIP/carol-.*'<br>+            count: 1<br>+    # Ensure carol exits the Stasis app. Then hang up the local replacement<br>+    # channel half in Stasis bridge 'test_bridge_a'.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: StasisEnd<br>+                application: 'testsuite'<br>+                channel:<br>+                    name: 'PJSIP/carol-.*'<br>+                    dialplan:<br>+                        exten: 'stasis_two'<br>+            count: 1<br>+        ami-actions:<br>+            action:<br>+               action: 'Hangup'<br>+               channel: '/^Local/_attended@transfer-.*;1$/'<br>+    # Ensure the local channel half that was bridged with bob in the Stasis<br>+    # bridge leaves the bridge.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: ChannelLeftBridge<br>+                application: 'testsuite'<br>+                bridge:<br>+                    id: 'test_bridge_a'<br>+                channel:<br>+                    name: 'Local/_attended@transfer-.*;1'<br>+            count: 1<br>+    # Ensure the local channel half that was bridged with bob exits the Stasis<br>+    # app.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: StasisEnd<br>+                application: 'testsuite'<br>+                channel:<br>+                    name: 'Local/_attended@transfer-.*;1'<br>+                    dialplan:<br>+                        exten: '_attended'<br>+            count: 1<br>+    # Ensure the other local channel half that was bridged with carol in the<br>+    # Stasis bridge leaves the bridge.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: ChannelLeftBridge<br>+                application: 'testsuite'<br>+                bridge:<br>+                    id: 'test_bridge_b'<br>+                channel:<br>+                    name: 'Local/_attended@transfer-.*;2'<br>+            count: 1<br>+    # Ensure the local channel half that was bridged with carol exits the<br>+    # Stasis app. Then hang up the kickoff local channel halves and destroy the<br>+    # Stasis bridge.<br>+    -<br>+        ari-events:<br>+            match:<br>+                type: StasisEnd<br>+                application: 'testsuite'<br>+                channel:<br>+                    name: 'Local/_attended@transfer-.*;2'<br>+                    dialplan:<br>+                        exten: '_attended'<br>+            count: 1<br>+        ami-actions:<br>+            action:<br>+               action: 'Hangup'<br>+               channel: '/^Local/dummy@default-.*;2$/'<br>+        ari-requests:<br>+            method: 'delete'<br>+            uri: 'bridges/test_bridge_a'<br>+            method: 'delete'<br>+            uri: 'bridges/test_bridge_b'<br>+<br>+properties:<br>+    minversion: '13.5.0'<br>+    dependencies:<br>+        - python : autobahn.websocket<br>+        - python : requests<br>+        - python : twisted<br>+        - python : starpy<br>+        - python : pjsua<br>+        - asterisk : app_stasis<br>+        - asterisk : res_ari_channels<br>+        - asterisk : res_ari_bridges<br>+        - asterisk : res_pjsip<br>+    tags:<br>+        - ARI<br>+        - pjsip<br>diff --git a/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/tests.yaml b/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/tests.yaml<br>index 15ba94e..989626a 100644<br>--- a/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/tests.yaml<br>+++ b/tests/rest_api/external_interaction/attended_transfer/stasis_bridge_to_stasis_bridge/tests.yaml<br>@@ -1,4 +1,5 @@<br> tests:<br>     - test: 'same_stasis_app'<br>+    - test: 'same_stasis_app_accepted'<br>     - test: 'different_stasis_app'<br> <br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/5823">change 5823</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/5823"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: testsuite </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: Ifbf1d6e8f91dfc00128a2ccd7eaff6402d170650 </div>
<div style="display:none"> Gerrit-Change-Number: 5823 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Richard Mudgett <rmudgett@digium.com> </div>