<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>