Skip to content

Commit 496d8d6

Browse files
Add tests for stasis_broadcast modules
Tests parallel broadcast to multiple ARI applications and verifies first-claim-wins semantics, CallBroadcast and CallClaimed event generation, and proper channel control transfer to the claiming app. The test: - Originates a channel that calls StasisBroadcast() - Verifies CallBroadcast event is sent to multiple apps - Claims the channel via POST /ari/events/claim - Verifies CallClaimed event is sent - Confirms channel enters Stasis in the claiming app"
1 parent 3877a8f commit 496d8d6

3 files changed

Lines changed: 169 additions & 0 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[default]
2+
exten => broadcast,1,NoOp()
3+
same => n,StasisBroadcast(,5000)
4+
same => n,Hangup()
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#!/usr/bin/env python
2+
'''Test Stasis broadcast and claim functionality'''
3+
4+
import sys
5+
import logging
6+
7+
sys.path.append("lib/python")
8+
9+
from twisted.internet import reactor
10+
from asterisk.test_case import TestCase
11+
12+
LOGGER = logging.getLogger(__name__)
13+
14+
TEST_TIMEOUT = 30
15+
16+
17+
class StasisBroadcastTest(TestCase):
18+
"""Test case for Stasis broadcast functionality"""
19+
20+
def __init__(self):
21+
"""Constructor"""
22+
super(StasisBroadcastTest, self).__init__()
23+
self.broadcast_received = False
24+
self.claim_received = False
25+
self.channel_id = None
26+
self.create_asterisk()
27+
28+
def ami_connect(self, ami):
29+
"""Called when AMI connects - originate the test call"""
30+
super(StasisBroadcastTest, self).ami_connect(ami)
31+
32+
LOGGER.info("AMI connected, originating call")
33+
ami.originate(
34+
channel="Local/broadcast@default",
35+
application="Echo"
36+
).addErrback(self.handle_originate_failure)
37+
38+
def ari_on_start(self, event):
39+
"""Called when a StasisStart event is received"""
40+
LOGGER.info("StasisStart received: %s" % event)
41+
self.channel_id = event['channel']['id']
42+
# Test passes when we get StasisStart after claim
43+
if self.claim_received:
44+
LOGGER.info("Test complete - channel entered Stasis after claim")
45+
self.stop_reactor()
46+
47+
def ari_on_broadcast(self, event):
48+
"""Called when a CallBroadcast event is received"""
49+
LOGGER.info("CallBroadcast received: %s" % event)
50+
self.broadcast_received = True
51+
self.channel_id = event['channel']['id']
52+
53+
# Attempt to claim the channel via POST /ari/events/claim
54+
ari = self.ari.userDefines['app']
55+
d = ari.post('events', 'claim',
56+
channel_id=self.channel_id,
57+
app='testsuite-app1')
58+
d.addCallback(self.claim_success)
59+
d.addErrback(self.claim_failure)
60+
61+
def ari_on_claimed(self, event):
62+
"""Called when a CallClaimed event is received"""
63+
LOGGER.info("CallClaimed received: %s" % event)
64+
self.claim_received = True
65+
# Wait for StasisStart to arrive after claim
66+
67+
def claim_success(self, result):
68+
"""Claim succeeded"""
69+
LOGGER.info("Claim request succeeded")
70+
71+
def claim_failure(self, reason):
72+
"""Claim failed"""
73+
LOGGER.error("Claim request failed: %s" % reason)
74+
self.stop_reactor()
75+
76+
def handle_originate_failure(self, reason):
77+
"""Called if originate fails"""
78+
LOGGER.error("Originate failed: %s" % reason)
79+
self.stop_reactor()
80+
81+
def run(self):
82+
"""Run the test"""
83+
super(StasisBroadcastTest, self).run()
84+
self.create_ami_factory()
85+
86+
# Set timeout
87+
reactor.callLater(TEST_TIMEOUT, self.timeout_test)
88+
89+
def timeout_test(self):
90+
"""Called if test times out"""
91+
LOGGER.error("Test timed out")
92+
self.stop_reactor()
93+
94+
95+
def main():
96+
"""Main entry point"""
97+
test = StasisBroadcastTest()
98+
test.start_asterisk()
99+
reactor.run()
100+
test.stop_asterisk()
101+
102+
if not test.passed:
103+
return 1
104+
return 0
105+
106+
107+
if __name__ == "__main__":
108+
sys.exit(main() or 0)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
testinfo:
2+
summary: 'Test Stasis broadcast and claim functionality'
3+
description: |
4+
Tests that channels can be broadcast to multiple ARI applications
5+
and that first-claim-wins semantics work correctly. Verifies
6+
CallBroadcast and CallClaimed events are generated.
7+
8+
test-modules:
9+
test-object:
10+
config-section: test-object-config
11+
typename: 'ari.AriOriginateTestObject'
12+
modules:
13+
-
14+
config-section: ari-config
15+
typename: 'ari.WebSocketEventModule'
16+
17+
test-object-config:
18+
stop-on-end: False
19+
20+
ari-config:
21+
apps: 'testsuite-app1,testsuite-app2'
22+
events:
23+
-
24+
conditions:
25+
match:
26+
type: 'StasisStart'
27+
application: 'testsuite-app1'
28+
count: 0
29+
-
30+
conditions:
31+
match:
32+
type: 'CallBroadcast'
33+
count: '>0'
34+
-
35+
conditions:
36+
match:
37+
type: 'CallClaimed'
38+
count: 1
39+
-
40+
conditions:
41+
match:
42+
type: 'StasisStart'
43+
count: 1
44+
45+
properties:
46+
dependencies:
47+
- python: 'autobahn.websocket'
48+
- python: 'requests'
49+
- python: 'twisted'
50+
- python: 'starpy'
51+
- asterisk: 'res_ari_channels'
52+
- asterisk: 'res_ari_events'
53+
- asterisk: 'res_stasis_broadcast'
54+
- asterisk: 'app_stasis_broadcast'
55+
tags:
56+
- ARI
57+
- stasis

0 commit comments

Comments
 (0)