Skip to content

Commit 547572b

Browse files
res_pjsip_maintenance: Add tests for PJSIP endpoint maintenance mode
Adds tests for the res_pjsip_maintenance module, which provides per- endpoint runtime maintenance mode via AMI and CLI. inbound_rejection: enables maintenance mode on endpoint "alice" via the PJSIPSetMaintenance AMI action, then verifies that a new inbound INVITE is rejected with 503 Service Unavailable before reaching the dialplan. ami_actions: verifies the full AMI control plane - PJSIPSetMaintenance emits a PJSIPMaintenanceStatus event with Status: enabled, which in turn triggers PJSIPShowMaintenance, confirming the list response and PJSIPMaintenanceStatusComplete are correctly produced. outbound_blocking: enables maintenance mode on endpoint "alice" via PJSIPSetMaintenance, then fires an async AMI Originate to PJSIP/alice and verifies that OriginateResponse carries Response: Failure. No registered contact is required; the session_create supplement check in ast_sip_session_create_outgoing() fires before any contact or AOR lookup, so the origination is refused immediately without any SIP traffic being generated. Development was assisted by Claude (Anthropic). All generated code has been reviewed, tested, and is understood by the author.
1 parent a75c9c9 commit 547572b

13 files changed

Lines changed: 342 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
load => res_pjsip_maintenance.so
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[system]
2+
type=system
3+
timer_t1=100
4+
timer_b=6400
5+
6+
[global]
7+
type=global
8+
debug=yes
9+
10+
[local]
11+
type=transport
12+
protocol=udp
13+
bind=0.0.0.0
14+
15+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
16+
17+
; Endpoint "alice" exists only so that PJSIPSetMaintenance can validate
18+
; it via ast_sorcery_retrieve_by_id. No calls are made in this test.
19+
[alice]
20+
type=endpoint
21+
transport=local
22+
context=default
23+
disallow=all
24+
allow=ulaw
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
testinfo:
2+
summary: 'Test PJSIPSetMaintenance and PJSIPShowMaintenance AMI actions'
3+
description: |
4+
Verifies the full AMI control plane for res_pjsip_maintenance:
5+
6+
* PJSIPSetMaintenance State: on emits PJSIPMaintenanceStatus (enabled)
7+
* PJSIPShowMaintenance returns a PJSIPMaintenanceStatus list entry
8+
followed by PJSIPMaintenanceStatusComplete
9+
10+
Sequence:
11+
1. On AMI connect, fire PJSIPSetMaintenance for endpoint "alice".
12+
2. The resulting PJSIPMaintenanceStatus (enabled) notification triggers
13+
PJSIPShowMaintenance (with a known ActionID). trigger-on-count
14+
ensures this fires exactly once even though Show itself also emits
15+
a PJSIPMaintenanceStatus event.
16+
3. The test stops when PJSIPMaintenanceStatusComplete arrives with the
17+
expected ActionID.
18+
19+
test-modules:
20+
test-object:
21+
config-section: object-config
22+
typename: 'test_case.TestCaseModule'
23+
modules:
24+
-
25+
config-section: ami-config
26+
typename: 'pluggable_modules.EventActionModule'
27+
28+
object-config:
29+
reactor-timeout: 15
30+
connect-ami: True
31+
32+
ami-config:
33+
# Step 1: enable maintenance for "alice" via AMI
34+
-
35+
ami-start:
36+
ami-actions:
37+
action:
38+
Action: 'PJSIPSetMaintenance'
39+
Endpoint: 'alice'
40+
State: 'on'
41+
42+
# Step 2: when the State change notification event arrives, trigger
43+
# PJSIPShowMaintenance. trigger-on-count: True with count: '>1' (min=1)
44+
# ensures the action fires only on the *first* matching event
45+
# (count['event'] == min == 1); subsequent events - including the
46+
# PJSIPMaintenanceStatus emitted by the Show list response itself - do
47+
# not re-trigger the action (count==2, not equal to min==1).
48+
# count: '>1' (at-least-1) also keeps the end-of-test count check happy
49+
# when two matching events total have been received.
50+
-
51+
ami-events:
52+
conditions:
53+
match:
54+
Event: 'PJSIPMaintenanceStatus'
55+
Status: 'enabled'
56+
Endpoint: 'alice'
57+
count: '>1'
58+
trigger-on-count: True
59+
ami-actions:
60+
action:
61+
Action: 'PJSIPShowMaintenance'
62+
Endpoint: 'alice'
63+
ActionID: 'maint-show-01'
64+
65+
# Step 3: stop (pass) when the Show list-complete event arrives
66+
-
67+
ami-events:
68+
conditions:
69+
match:
70+
Event: 'PJSIPMaintenanceStatusComplete'
71+
requirements:
72+
match:
73+
ActionID: 'maint-show-01'
74+
count: 1
75+
stop_test:
76+
77+
properties:
78+
dependencies:
79+
- asterisk: 'res_pjsip'
80+
- asterisk: 'res_pjsip_maintenance'
81+
tags:
82+
- pjsip
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[default]
2+
; This dialplan is not reached during a maintenance-mode test; the
3+
; PJSIP maintenance module rejects the INVITE with 503 before Asterisk
4+
; ever matches a dialplan extension. The context is required by the
5+
; endpoint configuration.
6+
exten => alice,1,Answer()
7+
same => n,Wait(1)
8+
same => n,Hangup()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
load => res_pjsip_maintenance.so
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[system]
2+
type=system
3+
timer_t1=100
4+
timer_b=6400
5+
6+
[global]
7+
type=global
8+
debug=yes
9+
10+
[local]
11+
type=transport
12+
protocol=udp
13+
bind=0.0.0.0
14+
15+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
16+
17+
[alice]
18+
type=endpoint
19+
transport=local
20+
context=default
21+
direct_media=no
22+
disallow=all
23+
allow=ulaw
24+
25+
[alice-identify]
26+
type=identify
27+
endpoint=alice
28+
match=127.0.0.1
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?xml version="1.0" encoding="ISO-8859-1" ?>
2+
<!DOCTYPE scenario SYSTEM "sipp.dtd">
3+
4+
<!-- UAC scenario: send an INVITE and expect a 503 Service Unavailable.
5+
A brief pause at the start ensures the AMI PJSIPSetMaintenance action
6+
has been processed before the request reaches Asterisk. -->
7+
<scenario name="INVITE expecting 503 Service Unavailable">
8+
9+
<!-- Wait long enough for the AMI action to enable maintenance mode -->
10+
<pause milliseconds="2000"/>
11+
12+
<send retrans="500">
13+
<![CDATA[
14+
15+
INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
16+
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
17+
From: alice <sip:[service]@[local_ip]:[local_port]>;tag=[call_number]
18+
To: asterisk <sip:[service]@[remote_ip]:[remote_port]>
19+
Call-ID: [call_id]
20+
CSeq: 1 INVITE
21+
Contact: <sip:[service]@[local_ip]:[local_port];transport=[transport]>
22+
Max-Forwards: 70
23+
Subject: Maintenance Test
24+
Content-Length: 0
25+
26+
]]>
27+
</send>
28+
29+
<recv response="100" optional="true"/>
30+
31+
<recv response="503">
32+
</recv>
33+
34+
<send>
35+
<![CDATA[
36+
37+
ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
38+
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
39+
From: alice <sip:[service]@[local_ip]:[local_port]>;tag=[call_number]
40+
To: asterisk <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
41+
Call-ID: [call_id]
42+
CSeq: 1 ACK
43+
Contact: <sip:[service]@[local_ip]:[local_port];transport=[transport]>
44+
Max-Forwards: 70
45+
Content-Length: 0
46+
47+
]]>
48+
</send>
49+
50+
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
51+
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
52+
53+
</scenario>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
testinfo:
2+
summary: 'Test res_pjsip_maintenance rejects inbound INVITE with 503'
3+
description: |
4+
Places a PJSIP endpoint into maintenance mode via the AMI
5+
PJSIPSetMaintenance action and verifies that a new inbound INVITE
6+
from that endpoint is rejected with "503 Service Unavailable".
7+
The SIPp scenario pauses briefly after startup to allow the AMI
8+
action to complete before sending the INVITE.
9+
10+
test-modules:
11+
test-object:
12+
config-section: test-object-config
13+
typename: 'sipp.SIPpAMIActionTestCase'
14+
15+
test-object-config:
16+
memcheck-delay-stop: 7
17+
reactor-timeout: 30
18+
fail-on-any: True
19+
test-iterations:
20+
-
21+
scenarios:
22+
- { 'key-args': { 'scenario': 'invite_expect_503.xml',
23+
'-i': '127.0.0.1', '-p': '5061',
24+
'-s': 'alice' } }
25+
ami-action:
26+
delay: 0
27+
args:
28+
Action: 'PJSIPSetMaintenance'
29+
Endpoint: 'alice'
30+
State: 'on'
31+
32+
properties:
33+
dependencies:
34+
- sipp:
35+
version: 'v3.0'
36+
- asterisk: 'res_pjsip'
37+
- asterisk: 'res_pjsip_maintenance'
38+
tags:
39+
- pjsip
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
load => res_pjsip_maintenance.so
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[system]
2+
type=system
3+
timer_t1=100
4+
timer_b=6400
5+
6+
[global]
7+
type=global
8+
debug=yes
9+
10+
[local]
11+
type=transport
12+
protocol=udp
13+
bind=0.0.0.0
14+
15+
; Endpoint "alice" - no registered contact is needed. The session_create
16+
; supplement check in ast_sip_session_create_outgoing() fires before any
17+
; contact or AOR lookup, so the origination is refused immediately.
18+
[alice]
19+
type=endpoint
20+
transport=local
21+
context=default
22+
disallow=all
23+
allow=ulaw

0 commit comments

Comments
 (0)