Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions tests/rest_api/stasis_broadcast/configs/ast1/extensions.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[default]
exten => s,1,NoOp()
same => n,Answer()
same => n,Stasis(testsuite)
same => n,Hangup()

exten => trigger,1,NoOp()
same => n,Answer()
same => n,Stasis(testsuite-app1)
same => n,Hangup()

exten => broadcast,1,NoOp()
same => n,StasisBroadcast(timeout=1000,app_filter=^testsuite-.*)
same => n,GotoIf($["${BROADCAST_WINNER}"=""]?no_route)
same => n,Stasis(${BROADCAST_WINNER})
same => n,Hangup()
same => n(no_route),NoOp(No application claimed)
same => n,Hangup()
96 changes: 96 additions & 0 deletions tests/rest_api/stasis_broadcast/stasis_broadcast_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"""
Stasis broadcast test callbacks

Tests that channels can be broadcast to multiple ARI applications
and that first-claim-wins semantics work correctly.
"""

import logging

LOGGER = logging.getLogger(__name__)

channel_id = None
broadcast_received = False
claim_received = False
trigger_channel_id = None


def on_trigger_start(ari, event, test_object):
"""Handle the initial trigger channel entering Stasis - start the test"""
global trigger_channel_id

LOGGER.info("Trigger channel entered Stasis: %s" % event)
trigger_channel_id = event['channel']['id']

# Originate the channel that will be broadcast via AMI
LOGGER.info("Originating broadcast channel via AMI")
ami = test_object.ami[0]
ami.originate(
channel='Local/broadcast@default',
application='Echo',
timeout=30000
).addErrback(test_object.handle_originate_failure)

# Don't delete the trigger channel yet - keep it alive until broadcast completes

return True


def on_broadcast(ari, event, test_object):
"""Handle CallBroadcast event"""
global channel_id, broadcast_received

LOGGER.info("CallBroadcast received for app %s: %s" % (event['application'], event))
broadcast_received = True
channel_id = event['channel']['id']

# Each app that receives the broadcast tries to claim - first one wins
LOGGER.info("Attempting to claim channel %s for application %s" % (channel_id, event['application']))
try:
ari.post('events/claim', channelId=channel_id, application=event['application'])
LOGGER.info("Claim succeeded for %s" % event['application'])
except Exception as e:
# 404 or 409 is expected if another app claimed first - this is normal!
LOGGER.info("Claim failed for %s (expected if another app won): %s" % (event['application'], e))

return True


def on_claimed(ari, event, test_object):
"""Handle CallClaimed event"""
global claim_received

LOGGER.info("CallClaimed received: %s" % event)
claim_received = True

return True


def on_start(ari, event, test_object):
"""Handle StasisStart event - channel entered Stasis after being claimed"""
global channel_id, claim_received, broadcast_received, trigger_channel_id

LOGGER.info("StasisStart received: %s" % event)
channel_id = event['channel']['id']

# Test passes when we get StasisStart after broadcast and claim
if broadcast_received and claim_received:
LOGGER.info("SUCCESS: Channel entered Stasis after being claimed")
# Delete both the broadcast channel and the trigger channel
try:
ari.delete('channels', channel_id)
except Exception as e:
LOGGER.info("Broadcast channel delete failed (may have already hung up): %s" % e)
try:
if trigger_channel_id:
ari.delete('channels', trigger_channel_id)
except Exception as e:
LOGGER.info("Trigger channel delete failed (may have already hung up): %s" % e)
test_object.set_passed(True)
test_object.stop_reactor()
else:
LOGGER.error("StasisStart received but broadcast/claim not complete")
test_object.set_passed(False)
test_object.stop_reactor()

return True
79 changes: 79 additions & 0 deletions tests/rest_api/stasis_broadcast/test-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
testinfo:
summary: 'Test Stasis broadcast and claim functionality'
description: |
Tests that channels can be broadcast to multiple ARI applications
and that first-claim-wins semantics work correctly. Verifies
CallBroadcast and CallClaimed events are generated.

test-modules:
add-test-to-search-path: True
test-object:
config-section: test-object-config
typename: 'ari.AriTestObject'
modules:
-
config-section: ari-config
typename: 'ari.WebSocketEventModule'

test-object-config:
apps: testsuite,testsuite-app1,testsuite-app2
stop-on-end: True
test-iterations:
-
channel: 'Local/s@default'
application: 'Echo'

ari-config:
apps: testsuite,testsuite-app1,testsuite-app2
events:
-
conditions:
match:
type: 'StasisStart'
application: 'testsuite'
args: []
channel:
name: 'Local/s@default.*'
count: 1
callback:
module: stasis_broadcast_test
method: on_trigger_start
-
conditions:
match:
type: 'CallBroadcast'
count: 2
callback:
module: stasis_broadcast_test
method: on_broadcast
-
conditions:
match:
type: 'CallClaimed'
count: 3
callback:
module: stasis_broadcast_test
method: on_claimed
-
conditions:
match:
type: 'StasisStart'
application: 'testsuite-app1'
count: 1
callback:
module: stasis_broadcast_test
method: on_start

properties:
dependencies:
- python: 'autobahn.websocket'
- python: 'requests'
- python: 'twisted'
- python: 'starpy'
- asterisk: 'res_ari_channels'
- asterisk: 'res_ari_events'
- asterisk: 'res_stasis_broadcast'
- asterisk: 'app_stasis_broadcast'
tags:
- ARI
- stasis
1 change: 1 addition & 0 deletions tests/rest_api/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ tests:
- dir: 'message'
- dir: 'external_interaction'
- test: 'move'
- test: 'stasis_broadcast'