[Asterisk-code-review] chan pjsip: Creating Channel Causes Asterisk to Crash When D... (testsuite[master])

Ashley Sanders asteriskteam at digium.com
Thu Apr 23 15:24:46 CDT 2015


Ashley Sanders has uploaded a new change for review.

  https://gerrit.asterisk.org/241

Change subject: chan_pjsip: Creating Channel Causes Asterisk to Crash When Duplicate AOR Sections Exist in pjsip.conf
......................................................................

chan_pjsip: Creating Channel Causes Asterisk to Crash When Duplicate AOR Sections Exist in pjsip.conf

This test contains two tests: [duplicate_sections] and [happy_config].

For the [duplicate_sections] test:
This test ensures Asterisk gracefully handles the situation where duplicate
sections are defined in pjsip.conf. Eleven (11) test scenarios are utilized to
confirm configuring pjsip.conf with sections containing an identical id/type
combination as another section in the file, results in Asterisk rejecting the
configuration. Each test scenario uses its own Asterisk instance to exercise a
different id/type combination.

The test scenarios:
Scenario [1]  -> ast1:  Tests duplicate [id=siptrunk, type=global] sections
Scenario [2]  -> ast2:  Tests duplicate [id=siptrunk, type=acl-template] sections
Scenario [3]  -> ast3:  Tests duplicate [id=siptrunk, type=aor-template] sections
Scenario [4]  -> ast4:  Tests duplicate [id=siptrunk, type=auth-template] sections
Scenario [5]  -> ast5:  Tests duplicate [id=siptrunk, type=contact-template] sections
Scenario [6]  -> ast6:  Tests duplicate [id=siptrunk, type=domain-alias-template] sections
Scenario [7]  -> ast7:  Tests duplicate [id=siptrunk, type=endpoint-template] sections
Scenario [8]  -> ast8:  Tests duplicate [id=siptrunk, type=identify-template] sections
Scenario [9]  -> ast9:  Tests duplicate [id=siptrunk, type=registration-template] sections
Scenario [10] -> ast10: Tests duplicate [id=siptrunk, type=system-template] sections
Scenario [11] -> ast11: Tests duplicate [id=siptrunk, type=transport-template] sections

For the [happy_config] test:
This test uses a pjsip.conf that represents the unique sections from the base
configuration for the [duplicate_sections] test, to ensure Asterisk does not
misidentify and reject a correct configuration.

ASTERISK-24996
Reported By: Ashley Sanders

Change-Id: I36078aae985050cff323ace3ccfd7464fe1de35f
---
A tests/channels/pjsip/configuration/duplicate_sections/configs/ast1/pjsip.conf
A tests/channels/pjsip/configuration/duplicate_sections/configs/ast10/pjsip.conf
A tests/channels/pjsip/configuration/duplicate_sections/configs/ast11/pjsip.conf
A tests/channels/pjsip/configuration/duplicate_sections/configs/ast2/pjsip.conf
A tests/channels/pjsip/configuration/duplicate_sections/configs/ast3/pjsip.conf
A tests/channels/pjsip/configuration/duplicate_sections/configs/ast4/pjsip.conf
A tests/channels/pjsip/configuration/duplicate_sections/configs/ast5/pjsip.conf
A tests/channels/pjsip/configuration/duplicate_sections/configs/ast6/pjsip.conf
A tests/channels/pjsip/configuration/duplicate_sections/configs/ast7/pjsip.conf
A tests/channels/pjsip/configuration/duplicate_sections/configs/ast8/pjsip.conf
A tests/channels/pjsip/configuration/duplicate_sections/configs/ast9/pjsip.conf
A tests/channels/pjsip/configuration/duplicate_sections/duplicate_sections.py
A tests/channels/pjsip/configuration/duplicate_sections/test-config.yaml
A tests/channels/pjsip/configuration/happy_config/configs/ast1/pjsip.conf
A tests/channels/pjsip/configuration/happy_config/happy_config.py
A tests/channels/pjsip/configuration/happy_config/test-config.yaml
A tests/channels/pjsip/configuration/test_harness.py
A tests/channels/pjsip/configuration/test_scenario.py
A tests/channels/pjsip/configuration/tests.yaml
M tests/channels/pjsip/tests.yaml
20 files changed, 1,907 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.asterisk.org:29418/testsuite refs/changes/41/241/1

diff --git a/tests/channels/pjsip/configuration/duplicate_sections/configs/ast1/pjsip.conf b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast1/pjsip.conf
new file mode 100644
index 0000000..65acd4e
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast1/pjsip.conf
@@ -0,0 +1,124 @@
+[global]
+type=global
+debug=yes
+
+[acl-template](!)
+type=acl
+contactdeny=0.0.0.0/0.0.0.0
+
+[aor-template](!)
+type=aor
+default_expiration=240
+max_contacts=5
+minimum_expiration=240
+maximum_expiration=3600
+qualify_frequency=900
+
+[auth-template](!)
+type=auth
+auth_type=userpass
+realm=asterisk
+
+[contact-template](!)
+type=contact
+qualify_frequency=0
+
+[domain-alias-template](!)
+type=domain_alias
+
+[endpoint-template](!)
+type=endpoint
+transport=trans
+disallow=all
+allow=ulaw
+allow_subscribe=yes
+allow_transfer=yes
+callerid=uut_callerid_name <uut_callerid_num>
+callerid_privacy=allowed
+connected_line_method=invite
+context=local
+device_state_busy_at=0
+direct_media=no
+fax_detect=no
+force_rport=yes
+from_domain=
+from_user=
+rewrite_contact=no
+t38_udptl=no
+t38_udptl_ec=none
+t38_udptl_ipv6=no
+t38_udptl_maxdatagram=0
+t38_udptl_nat=no
+trust_id_inbound=no
+trust_id_outbound=no
+
+[identify-template](!)
+type=identify
+
+[registration-template](!)
+type=registration
+auth_rejection_permanent=no
+expiration=3600
+forbidden_retry_interval=0
+max_retries=10
+outbound_proxy=
+retry_interval=60
+
+[system-template](!)
+type=system
+
+[transport-template](!)
+type=transport
+protocol=udp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](acl-template)
+contactpermit=127.0.0.1
+
+[siptrunk](aor-template)
+contact=siptrunk
+mailboxes=4000 at default
+
+[siptrunk](auth-template)
+username=foo
+password=bar
+
+[siptrunk](contact-template)
+contact=sip:siptrunk at 127.0.0.1:5062
+
+[siptrunk](domain-alias-template)
+domain=foo.com
+
+[siptrunk](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
+
+[siptrunk](identify-template)
+endpoint=siptrunk
+match=127.0.0.1
+
+[siptrunk](registration-template)
+client_uri=sip:siptrunk at 127.0.0.1:5061
+server_uri=siptrunk
+contact_user=siptrunk
+outbound_auth=siptrunk
+transport=siptrunk
+
+[siptrunk](system-template)
+timer_t1=500
+timer_b=32000
+compact_headers=no
+
+[siptrunk](transport-template)
+bind=127.0.0.1:5061
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; duplicate entry
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[global]
+type=global
+debug=yes
diff --git a/tests/channels/pjsip/configuration/duplicate_sections/configs/ast10/pjsip.conf b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast10/pjsip.conf
new file mode 100644
index 0000000..2093f83
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast10/pjsip.conf
@@ -0,0 +1,125 @@
+[global]
+type=global
+debug=yes
+
+[acl-template](!)
+type=acl
+contactdeny=0.0.0.0/0.0.0.0
+
+[aor-template](!)
+type=aor
+default_expiration=240
+max_contacts=5
+minimum_expiration=240
+maximum_expiration=3600
+qualify_frequency=900
+
+[auth-template](!)
+type=auth
+auth_type=userpass
+realm=asterisk
+
+[contact-template](!)
+type=contact
+qualify_frequency=0
+
+[domain-alias-template](!)
+type=domain_alias
+
+[endpoint-template](!)
+type=endpoint
+transport=trans
+disallow=all
+allow=ulaw
+allow_subscribe=yes
+allow_transfer=yes
+callerid=uut_callerid_name <uut_callerid_num>
+callerid_privacy=allowed
+connected_line_method=invite
+context=local
+device_state_busy_at=0
+direct_media=no
+fax_detect=no
+force_rport=yes
+from_domain=
+from_user=
+rewrite_contact=no
+t38_udptl=no
+t38_udptl_ec=none
+t38_udptl_ipv6=no
+t38_udptl_maxdatagram=0
+t38_udptl_nat=no
+trust_id_inbound=no
+trust_id_outbound=no
+
+[identify-template](!)
+type=identify
+
+[registration-template](!)
+type=registration
+auth_rejection_permanent=no
+expiration=3600
+forbidden_retry_interval=0
+max_retries=10
+outbound_proxy=
+retry_interval=60
+
+[system-template](!)
+type=system
+
+[transport-template](!)
+type=transport
+protocol=udp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](acl-template)
+contactpermit=127.0.0.10
+
+[siptrunk](aor-template)
+contact=siptrunk
+mailboxes=4000 at default
+
+[siptrunk](auth-template)
+username=foo
+password=bar
+
+[siptrunk](contact-template)
+contact=sip:siptrunk at 127.0.0.10:5062
+
+[siptrunk](domain-alias-template)
+domain=foo.com
+
+[siptrunk](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
+
+[siptrunk](identify-template)
+endpoint=siptrunk
+match=127.0.0.10
+
+[siptrunk](registration-template)
+client_uri=sip:siptrunk at 127.0.0.10:5061
+server_uri=siptrunk
+contact_user=siptrunk
+outbound_auth=siptrunk
+transport=siptrunk
+
+[siptrunk](system-template)
+timer_t1=500
+timer_b=32000
+compact_headers=no
+
+[siptrunk](transport-template)
+bind=127.0.0.10:5061
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; duplicate entry
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](system-template)
+timer_t1=500
+timer_b=32000
+compact_headers=no
\ No newline at end of file
diff --git a/tests/channels/pjsip/configuration/duplicate_sections/configs/ast11/pjsip.conf b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast11/pjsip.conf
new file mode 100644
index 0000000..5fe21af
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast11/pjsip.conf
@@ -0,0 +1,123 @@
+[global]
+type=global
+debug=yes
+
+[acl-template](!)
+type=acl
+contactdeny=0.0.0.0/0.0.0.0
+
+[aor-template](!)
+type=aor
+default_expiration=240
+max_contacts=5
+minimum_expiration=240
+maximum_expiration=3600
+qualify_frequency=900
+
+[auth-template](!)
+type=auth
+auth_type=userpass
+realm=asterisk
+
+[contact-template](!)
+type=contact
+qualify_frequency=0
+
+[domain-alias-template](!)
+type=domain_alias
+
+[endpoint-template](!)
+type=endpoint
+transport=trans
+disallow=all
+allow=ulaw
+allow_subscribe=yes
+allow_transfer=yes
+callerid=uut_callerid_name <uut_callerid_num>
+callerid_privacy=allowed
+connected_line_method=invite
+context=local
+device_state_busy_at=0
+direct_media=no
+fax_detect=no
+force_rport=yes
+from_domain=
+from_user=
+rewrite_contact=no
+t38_udptl=no
+t38_udptl_ec=none
+t38_udptl_ipv6=no
+t38_udptl_maxdatagram=0
+t38_udptl_nat=no
+trust_id_inbound=no
+trust_id_outbound=no
+
+[identify-template](!)
+type=identify
+
+[registration-template](!)
+type=registration
+auth_rejection_permanent=no
+expiration=3600
+forbidden_retry_interval=0
+max_retries=10
+outbound_proxy=
+retry_interval=60
+
+[system-template](!)
+type=system
+
+[transport-template](!)
+type=transport
+protocol=udp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](acl-template)
+contactpermit=127.0.0.11
+
+[siptrunk](aor-template)
+contact=siptrunk
+mailboxes=4000 at default
+
+[siptrunk](auth-template)
+username=foo
+password=bar
+
+[siptrunk](contact-template)
+contact=sip:siptrunk at 127.0.0.11:5062
+
+[siptrunk](domain-alias-template)
+domain=foo.com
+
+[siptrunk](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
+
+[siptrunk](identify-template)
+endpoint=siptrunk
+match=127.0.0.11
+
+[siptrunk](registration-template)
+client_uri=sip:siptrunk at 127.0.0.11:5061
+server_uri=siptrunk
+contact_user=siptrunk
+outbound_auth=siptrunk
+transport=siptrunk
+
+[siptrunk](system-template)
+timer_t1=500
+timer_b=32000
+compact_headers=no
+
+[siptrunk](transport-template)
+bind=127.0.0.11:5061
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; duplicate entry
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](transport-template)
+bind=127.0.0.11:5061
\ No newline at end of file
diff --git a/tests/channels/pjsip/configuration/duplicate_sections/configs/ast2/pjsip.conf b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast2/pjsip.conf
new file mode 100644
index 0000000..d766b53
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast2/pjsip.conf
@@ -0,0 +1,123 @@
+[global]
+type=global
+debug=yes
+
+[acl-template](!)
+type=acl
+contactdeny=0.0.0.0/0.0.0.0
+
+[aor-template](!)
+type=aor
+default_expiration=240
+max_contacts=5
+minimum_expiration=240
+maximum_expiration=3600
+qualify_frequency=900
+
+[auth-template](!)
+type=auth
+auth_type=userpass
+realm=asterisk
+
+[contact-template](!)
+type=contact
+qualify_frequency=0
+
+[domain-alias-template](!)
+type=domain_alias
+
+[endpoint-template](!)
+type=endpoint
+transport=trans
+disallow=all
+allow=ulaw
+allow_subscribe=yes
+allow_transfer=yes
+callerid=uut_callerid_name <uut_callerid_num>
+callerid_privacy=allowed
+connected_line_method=invite
+context=local
+device_state_busy_at=0
+direct_media=no
+fax_detect=no
+force_rport=yes
+from_domain=
+from_user=
+rewrite_contact=no
+t38_udptl=no
+t38_udptl_ec=none
+t38_udptl_ipv6=no
+t38_udptl_maxdatagram=0
+t38_udptl_nat=no
+trust_id_inbound=no
+trust_id_outbound=no
+
+[identify-template](!)
+type=identify
+
+[registration-template](!)
+type=registration
+auth_rejection_permanent=no
+expiration=3600
+forbidden_retry_interval=0
+max_retries=10
+outbound_proxy=
+retry_interval=60
+
+[system-template](!)
+type=system
+
+[transport-template](!)
+type=transport
+protocol=udp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](acl-template)
+contactpermit=127.0.0.2
+
+[siptrunk](aor-template)
+contact=siptrunk
+mailboxes=4000 at default
+
+[siptrunk](auth-template)
+username=foo
+password=bar
+
+[siptrunk](contact-template)
+contact=sip:siptrunk at 127.0.0.2:5062
+
+[siptrunk](domain-alias-template)
+domain=foo.com
+
+[siptrunk](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
+
+[siptrunk](identify-template)
+endpoint=siptrunk
+match=127.0.0.2
+
+[siptrunk](registration-template)
+client_uri=sip:siptrunk at 127.0.0.2:5061
+server_uri=siptrunk
+contact_user=siptrunk
+outbound_auth=siptrunk
+transport=siptrunk
+
+[siptrunk](system-template)
+timer_t1=500
+timer_b=32000
+compact_headers=no
+
+[siptrunk](transport-template)
+bind=127.0.0.2:5061
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; duplicate entry
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](acl-template)
+contactpermit=127.0.0.2
diff --git a/tests/channels/pjsip/configuration/duplicate_sections/configs/ast3/pjsip.conf b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast3/pjsip.conf
new file mode 100644
index 0000000..b1bd584
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast3/pjsip.conf
@@ -0,0 +1,124 @@
+[global]
+type=global
+debug=yes
+
+[acl-template](!)
+type=acl
+contactdeny=0.0.0.0/0.0.0.0
+
+[aor-template](!)
+type=aor
+default_expiration=240
+max_contacts=5
+minimum_expiration=240
+maximum_expiration=3600
+qualify_frequency=900
+
+[auth-template](!)
+type=auth
+auth_type=userpass
+realm=asterisk
+
+[contact-template](!)
+type=contact
+qualify_frequency=0
+
+[domain-alias-template](!)
+type=domain_alias
+
+[endpoint-template](!)
+type=endpoint
+transport=trans
+disallow=all
+allow=ulaw
+allow_subscribe=yes
+allow_transfer=yes
+callerid=uut_callerid_name <uut_callerid_num>
+callerid_privacy=allowed
+connected_line_method=invite
+context=local
+device_state_busy_at=0
+direct_media=no
+fax_detect=no
+force_rport=yes
+from_domain=
+from_user=
+rewrite_contact=no
+t38_udptl=no
+t38_udptl_ec=none
+t38_udptl_ipv6=no
+t38_udptl_maxdatagram=0
+t38_udptl_nat=no
+trust_id_inbound=no
+trust_id_outbound=no
+
+[identify-template](!)
+type=identify
+
+[registration-template](!)
+type=registration
+auth_rejection_permanent=no
+expiration=3600
+forbidden_retry_interval=0
+max_retries=10
+outbound_proxy=
+retry_interval=60
+
+[system-template](!)
+type=system
+
+[transport-template](!)
+type=transport
+protocol=udp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](acl-template)
+contactpermit=127.0.0.3
+
+[siptrunk](aor-template)
+contact=siptrunk
+mailboxes=4000 at default
+
+[siptrunk](auth-template)
+username=foo
+password=bar
+
+[siptrunk](contact-template)
+contact=sip:siptrunk at 127.0.0.3:5062
+
+[siptrunk](domain-alias-template)
+domain=foo.com
+
+[siptrunk](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
+
+[siptrunk](identify-template)
+endpoint=siptrunk
+match=127.0.0.3
+
+[siptrunk](registration-template)
+client_uri=sip:siptrunk at 127.0.0.3:5061
+server_uri=siptrunk
+contact_user=siptrunk
+outbound_auth=siptrunk
+transport=siptrunk
+
+[siptrunk](system-template)
+timer_t1=500
+timer_b=32000
+compact_headers=no
+
+[siptrunk](transport-template)
+bind=127.0.0.3:5061
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; duplicate entry
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](aor-template)
+contact=siptrunk
+mailboxes=4000 at default
diff --git a/tests/channels/pjsip/configuration/duplicate_sections/configs/ast4/pjsip.conf b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast4/pjsip.conf
new file mode 100644
index 0000000..269f6a2
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast4/pjsip.conf
@@ -0,0 +1,124 @@
+[global]
+type=global
+debug=yes
+
+[acl-template](!)
+type=acl
+contactdeny=0.0.0.0/0.0.0.0
+
+[aor-template](!)
+type=aor
+default_expiration=240
+max_contacts=5
+minimum_expiration=240
+maximum_expiration=3600
+qualify_frequency=900
+
+[auth-template](!)
+type=auth
+auth_type=userpass
+realm=asterisk
+
+[contact-template](!)
+type=contact
+qualify_frequency=0
+
+[domain-alias-template](!)
+type=domain_alias
+
+[endpoint-template](!)
+type=endpoint
+transport=trans
+disallow=all
+allow=ulaw
+allow_subscribe=yes
+allow_transfer=yes
+callerid=uut_callerid_name <uut_callerid_num>
+callerid_privacy=allowed
+connected_line_method=invite
+context=local
+device_state_busy_at=0
+direct_media=no
+fax_detect=no
+force_rport=yes
+from_domain=
+from_user=
+rewrite_contact=no
+t38_udptl=no
+t38_udptl_ec=none
+t38_udptl_ipv6=no
+t38_udptl_maxdatagram=0
+t38_udptl_nat=no
+trust_id_inbound=no
+trust_id_outbound=no
+
+[identify-template](!)
+type=identify
+
+[registration-template](!)
+type=registration
+auth_rejection_permanent=no
+expiration=3600
+forbidden_retry_interval=0
+max_retries=10
+outbound_proxy=
+retry_interval=60
+
+[system-template](!)
+type=system
+
+[transport-template](!)
+type=transport
+protocol=udp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](acl-template)
+contactpermit=127.0.0.4
+
+[siptrunk](aor-template)
+contact=siptrunk
+mailboxes=4000 at default
+
+[siptrunk](auth-template)
+username=foo
+password=bar
+
+[siptrunk](contact-template)
+contact=sip:siptrunk at 127.0.0.4:5062
+
+[siptrunk](domain-alias-template)
+domain=foo.com
+
+[siptrunk](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
+
+[siptrunk](identify-template)
+endpoint=siptrunk
+match=127.0.0.4
+
+[siptrunk](registration-template)
+client_uri=sip:siptrunk at 127.0.0.4:5061
+server_uri=siptrunk
+contact_user=siptrunk
+outbound_auth=siptrunk
+transport=siptrunk
+
+[siptrunk](system-template)
+timer_t1=500
+timer_b=32000
+compact_headers=no
+
+[siptrunk](transport-template)
+bind=127.0.0.4:5061
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; duplicate entry
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](auth-template)
+username=foo
+password=bar
diff --git a/tests/channels/pjsip/configuration/duplicate_sections/configs/ast5/pjsip.conf b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast5/pjsip.conf
new file mode 100644
index 0000000..0686f8d
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast5/pjsip.conf
@@ -0,0 +1,126 @@
+[global]
+type=global
+debug=yes
+
+[acl-template](!)
+type=acl
+contactdeny=0.0.0.0/0.0.0.0
+
+[aor-template](!)
+type=aor
+default_expiration=240
+max_contacts=5
+minimum_expiration=240
+maximum_expiration=3600
+qualify_frequency=900
+
+[auth-template](!)
+type=auth
+auth_type=userpass
+realm=asterisk
+
+[contact-template](!)
+type=contact
+qualify_frequency=0
+
+[domain-alias-template](!)
+type=domain_alias
+
+[endpoint-template](!)
+type=endpoint
+transport=trans
+disallow=all
+allow=ulaw
+allow_subscribe=yes
+allow_transfer=yes
+callerid=uut_callerid_name <uut_callerid_num>
+callerid_privacy=allowed
+connected_line_method=invite
+context=local
+device_state_busy_at=0
+direct_media=no
+fax_detect=no
+force_rport=yes
+from_domain=
+from_user=
+rewrite_contact=no
+t38_udptl=no
+t38_udptl_ec=none
+t38_udptl_ipv6=no
+t38_udptl_maxdatagram=0
+t38_udptl_nat=no
+trust_id_inbound=no
+trust_id_outbound=no
+
+[identify-template](!)
+type=identify
+
+[registration-template](!)
+type=registration
+auth_rejection_permanent=no
+expiration=3600
+forbidden_retry_interval=0
+max_retries=10
+outbound_proxy=
+retry_interval=60
+
+[system-template](!)
+type=system
+
+[transport-template](!)
+type=transport
+protocol=udp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](acl-template)
+contactpermit=127.0.0.5
+
+[siptrunk](aor-template)
+contact=siptrunk
+mailboxes=4000 at default
+
+[siptrunk](auth-template)
+username=foo
+password=bar
+
+[siptrunk](contact-template)
+contact=sip:siptrunk at 127.0.0.5:5062
+
+[siptrunk](domain-alias-template)
+domain=foo.com
+
+[siptrunk](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
+
+[siptrunk](identify-template)
+endpoint=siptrunk
+match=127.0.0.5
+
+[siptrunk](registration-template)
+client_uri=sip:siptrunk at 127.0.0.5:5061
+server_uri=siptrunk
+contact_user=siptrunk
+outbound_auth=siptrunk
+transport=siptrunk
+
+[siptrunk](system-template)
+timer_t1=500
+timer_b=32000
+compact_headers=no
+
+[siptrunk](transport-template)
+bind=127.0.0.5:5061
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; duplicate entry
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+[siptrunk](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
+
diff --git a/tests/channels/pjsip/configuration/duplicate_sections/configs/ast6/pjsip.conf b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast6/pjsip.conf
new file mode 100644
index 0000000..9fd1ea3
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast6/pjsip.conf
@@ -0,0 +1,123 @@
+[global]
+type=global
+debug=yes
+
+[acl-template](!)
+type=acl
+contactdeny=0.0.0.0/0.0.0.0
+
+[aor-template](!)
+type=aor
+default_expiration=240
+max_contacts=5
+minimum_expiration=240
+maximum_expiration=3600
+qualify_frequency=900
+
+[auth-template](!)
+type=auth
+auth_type=userpass
+realm=asterisk
+
+[contact-template](!)
+type=contact
+qualify_frequency=0
+
+[domain-alias-template](!)
+type=domain_alias
+
+[endpoint-template](!)
+type=endpoint
+transport=trans
+disallow=all
+allow=ulaw
+allow_subscribe=yes
+allow_transfer=yes
+callerid=uut_callerid_name <uut_callerid_num>
+callerid_privacy=allowed
+connected_line_method=invite
+context=local
+device_state_busy_at=0
+direct_media=no
+fax_detect=no
+force_rport=yes
+from_domain=
+from_user=
+rewrite_contact=no
+t38_udptl=no
+t38_udptl_ec=none
+t38_udptl_ipv6=no
+t38_udptl_maxdatagram=0
+t38_udptl_nat=no
+trust_id_inbound=no
+trust_id_outbound=no
+
+[identify-template](!)
+type=identify
+
+[registration-template](!)
+type=registration
+auth_rejection_permanent=no
+expiration=3600
+forbidden_retry_interval=0
+max_retries=10
+outbound_proxy=
+retry_interval=60
+
+[system-template](!)
+type=system
+
+[transport-template](!)
+type=transport
+protocol=udp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](acl-template)
+contactpermit=127.0.0.6
+
+[siptrunk](aor-template)
+contact=siptrunk
+mailboxes=4000 at default
+
+[siptrunk](auth-template)
+username=foo
+password=bar
+
+[siptrunk](contact-template)
+contact=sip:siptrunk at 127.0.0.6:5062
+
+[siptrunk](domain-alias-template)
+domain=foo.com
+
+[siptrunk](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
+
+[siptrunk](identify-template)
+endpoint=siptrunk
+match=127.0.0.6
+
+[siptrunk](registration-template)
+client_uri=sip:siptrunk at 127.0.0.6:5061
+server_uri=siptrunk
+contact_user=siptrunk
+outbound_auth=siptrunk
+transport=siptrunk
+
+[siptrunk](system-template)
+timer_t1=500
+timer_b=32000
+compact_headers=no
+
+[siptrunk](transport-template)
+bind=127.0.0.6:5061
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; duplicate entry
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](domain-alias-template)
+domain=foo.com
diff --git a/tests/channels/pjsip/configuration/duplicate_sections/configs/ast7/pjsip.conf b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast7/pjsip.conf
new file mode 100644
index 0000000..ac13a50
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast7/pjsip.conf
@@ -0,0 +1,126 @@
+[global]
+type=global
+debug=yes
+
+[acl-template](!)
+type=acl
+contactdeny=0.0.0.0/0.0.0.0
+
+[aor-template](!)
+type=aor
+default_expiration=240
+max_contacts=5
+minimum_expiration=240
+maximum_expiration=3600
+qualify_frequency=900
+
+[auth-template](!)
+type=auth
+auth_type=userpass
+realm=asterisk
+
+[contact-template](!)
+type=contact
+qualify_frequency=0
+
+[domain-alias-template](!)
+type=domain_alias
+
+[endpoint-template](!)
+type=endpoint
+transport=trans
+disallow=all
+allow=ulaw
+allow_subscribe=yes
+allow_transfer=yes
+callerid=uut_callerid_name <uut_callerid_num>
+callerid_privacy=allowed
+connected_line_method=invite
+context=local
+device_state_busy_at=0
+direct_media=no
+fax_detect=no
+force_rport=yes
+from_domain=
+from_user=
+rewrite_contact=no
+t38_udptl=no
+t38_udptl_ec=none
+t38_udptl_ipv6=no
+t38_udptl_maxdatagram=0
+t38_udptl_nat=no
+trust_id_inbound=no
+trust_id_outbound=no
+
+[identify-template](!)
+type=identify
+
+[registration-template](!)
+type=registration
+auth_rejection_permanent=no
+expiration=3600
+forbidden_retry_interval=0
+max_retries=10
+outbound_proxy=
+retry_interval=60
+
+[system-template](!)
+type=system
+
+[transport-template](!)
+type=transport
+protocol=udp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](acl-template)
+contactpermit=127.0.0.7
+
+[siptrunk](aor-template)
+contact=siptrunk
+mailboxes=4000 at default
+
+[siptrunk](auth-template)
+username=foo
+password=bar
+
+[siptrunk](contact-template)
+contact=sip:siptrunk at 127.0.0.7:5062
+
+[siptrunk](domain-alias-template)
+domain=foo.com
+
+[siptrunk](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
+
+[siptrunk](identify-template)
+endpoint=siptrunk
+match=127.0.0.7
+
+[siptrunk](registration-template)
+client_uri=sip:siptrunk at 127.0.0.7:5061
+server_uri=siptrunk
+contact_user=siptrunk
+outbound_auth=siptrunk
+transport=siptrunk
+
+[siptrunk](system-template)
+timer_t1=500
+timer_b=32000
+compact_headers=no
+
+[siptrunk](transport-template)
+bind=127.0.0.7:5061
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; duplicate entry
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
diff --git a/tests/channels/pjsip/configuration/duplicate_sections/configs/ast8/pjsip.conf b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast8/pjsip.conf
new file mode 100644
index 0000000..6c67b61
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast8/pjsip.conf
@@ -0,0 +1,124 @@
+[global]
+type=global
+debug=yes
+
+[acl-template](!)
+type=acl
+contactdeny=0.0.0.0/0.0.0.0
+
+[aor-template](!)
+type=aor
+default_expiration=240
+max_contacts=5
+minimum_expiration=240
+maximum_expiration=3600
+qualify_frequency=900
+
+[auth-template](!)
+type=auth
+auth_type=userpass
+realm=asterisk
+
+[contact-template](!)
+type=contact
+qualify_frequency=0
+
+[domain-alias-template](!)
+type=domain_alias
+
+[endpoint-template](!)
+type=endpoint
+transport=trans
+disallow=all
+allow=ulaw
+allow_subscribe=yes
+allow_transfer=yes
+callerid=uut_callerid_name <uut_callerid_num>
+callerid_privacy=allowed
+connected_line_method=invite
+context=local
+device_state_busy_at=0
+direct_media=no
+fax_detect=no
+force_rport=yes
+from_domain=
+from_user=
+rewrite_contact=no
+t38_udptl=no
+t38_udptl_ec=none
+t38_udptl_ipv6=no
+t38_udptl_maxdatagram=0
+t38_udptl_nat=no
+trust_id_inbound=no
+trust_id_outbound=no
+
+[identify-template](!)
+type=identify
+
+[registration-template](!)
+type=registration
+auth_rejection_permanent=no
+expiration=3600
+forbidden_retry_interval=0
+max_retries=10
+outbound_proxy=
+retry_interval=60
+
+[system-template](!)
+type=system
+
+[transport-template](!)
+type=transport
+protocol=udp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](acl-template)
+contactpermit=127.0.0.8
+
+[siptrunk](aor-template)
+contact=siptrunk
+mailboxes=4000 at default
+
+[siptrunk](auth-template)
+username=foo
+password=bar
+
+[siptrunk](contact-template)
+contact=sip:siptrunk at 127.0.0.8:5062
+
+[siptrunk](domain-alias-template)
+domain=foo.com
+
+[siptrunk](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
+
+[siptrunk](identify-template)
+endpoint=siptrunk
+match=127.0.0.8
+
+[siptrunk](registration-template)
+client_uri=sip:siptrunk at 127.0.0.8:5061
+server_uri=siptrunk
+contact_user=siptrunk
+outbound_auth=siptrunk
+transport=siptrunk
+
+[siptrunk](system-template)
+timer_t1=500
+timer_b=32000
+compact_headers=no
+
+[siptrunk](transport-template)
+bind=127.0.0.8:5061
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; duplicate entry
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](identify-template)
+endpoint=siptrunk
+match=127.0.0.8
\ No newline at end of file
diff --git a/tests/channels/pjsip/configuration/duplicate_sections/configs/ast9/pjsip.conf b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast9/pjsip.conf
new file mode 100644
index 0000000..0363c6e
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast9/pjsip.conf
@@ -0,0 +1,127 @@
+[global]
+type=global
+debug=yes
+
+[acl-template](!)
+type=acl
+contactdeny=0.0.0.0/0.0.0.0
+
+[aor-template](!)
+type=aor
+default_expiration=240
+max_contacts=5
+minimum_expiration=240
+maximum_expiration=3600
+qualify_frequency=900
+
+[auth-template](!)
+type=auth
+auth_type=userpass
+realm=asterisk
+
+[contact-template](!)
+type=contact
+qualify_frequency=0
+
+[domain-alias-template](!)
+type=domain_alias
+
+[endpoint-template](!)
+type=endpoint
+transport=trans
+disallow=all
+allow=ulaw
+allow_subscribe=yes
+allow_transfer=yes
+callerid=uut_callerid_name <uut_callerid_num>
+callerid_privacy=allowed
+connected_line_method=invite
+context=local
+device_state_busy_at=0
+direct_media=no
+fax_detect=no
+force_rport=yes
+from_domain=
+from_user=
+rewrite_contact=no
+t38_udptl=no
+t38_udptl_ec=none
+t38_udptl_ipv6=no
+t38_udptl_maxdatagram=0
+t38_udptl_nat=no
+trust_id_inbound=no
+trust_id_outbound=no
+
+[identify-template](!)
+type=identify
+
+[registration-template](!)
+type=registration
+auth_rejection_permanent=no
+expiration=3600
+forbidden_retry_interval=0
+max_retries=10
+outbound_proxy=
+retry_interval=60
+
+[system-template](!)
+type=system
+
+[transport-template](!)
+type=transport
+protocol=udp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](acl-template)
+contactpermit=127.0.0.9
+
+[siptrunk](aor-template)
+contact=siptrunk
+mailboxes=4000 at default
+
+[siptrunk](auth-template)
+username=foo
+password=bar
+
+[siptrunk](contact-template)
+contact=sip:siptrunk at 127.0.0.9:5062
+
+[siptrunk](domain-alias-template)
+domain=foo.com
+
+[siptrunk](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
+
+[siptrunk](identify-template)
+endpoint=siptrunk
+match=127.0.0.9
+
+[siptrunk](registration-template)
+client_uri=sip:siptrunk at 127.0.0.9:5061
+server_uri=siptrunk
+contact_user=siptrunk
+outbound_auth=siptrunk
+transport=siptrunk
+
+[siptrunk](system-template)
+timer_t1=500
+timer_b=32000
+compact_headers=no
+
+[siptrunk](transport-template)
+bind=127.0.0.9:5061
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; duplicate entry
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](registration-template)
+client_uri=sip:siptrunk at 127.0.0.9:5061
+server_uri=siptrunk
+contact_user=siptrunk
+outbound_auth=siptrunk
+transport=siptrunk
\ No newline at end of file
diff --git a/tests/channels/pjsip/configuration/duplicate_sections/duplicate_sections.py b/tests/channels/pjsip/configuration/duplicate_sections/duplicate_sections.py
new file mode 100755
index 0000000..2507c00
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/duplicate_sections.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+"""
+Copyright (C) 2015, Digium, Inc.
+Ashley Sanders <asanders at digium.com>
+
+This program is free software, distributed under the terms of
+the GNU General Public License Version 2.
+"""
+
+import sys
+
+sys.path.append("lib/python")
+sys.path.append("tests/channels/pjsip/configuration")
+
+from test_harness import TestHarness
+
+
+class DuplicateSectionsTestHarness(TestHarness):
+    """The test harness for the duplicate sections test."""
+
+    def __init__(self, config, test_object):
+        """Constructor.
+
+        Keyword Arguments:
+        config                 -- The YAML configuration for this test.
+        test_object            -- The TestCaseModule instance for this test.
+        """
+
+        super(DuplicateSectionsTestHarness, self).__init__(config,
+                                                           test_object)
diff --git a/tests/channels/pjsip/configuration/duplicate_sections/test-config.yaml b/tests/channels/pjsip/configuration/duplicate_sections/test-config.yaml
new file mode 100644
index 0000000..b248bfa
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/test-config.yaml
@@ -0,0 +1,55 @@
+testinfo:
+    summary: |
+        Ensures Asterisk correctly handles the situation where duplicate
+        entries are defined in pjsip.conf.
+    description: |
+        This test ensures Asterisk gracefully handles the situation where
+        duplicate sections are defined in pjsip.conf. Eleven (11) test
+        scenarios are utilized to confirm configuring pjsip.conf with sections
+        containing an identical id/type combination as another section in the
+        file, results in Asterisk rejecting the configuration. Each test
+        scenario uses its own Asterisk instance to exercise a different id/type
+        combination. The test scenarios:
+        Scenario [1]  -> ast1:  Tests duplicate [id=siptrunk, type=global] sections
+        Scenario [2]  -> ast2:  Tests duplicate [id=siptrunk, type=acl-template] sections
+        Scenario [3]  -> ast3:  Tests duplicate [id=siptrunk, type=aor-template] sections
+        Scenario [4]  -> ast4:  Tests duplicate [id=siptrunk, type=auth-template] sections
+        Scenario [5]  -> ast5:  Tests duplicate [id=siptrunk, type=contact-template] sections
+        Scenario [6]  -> ast6:  Tests duplicate [id=siptrunk, type=domain-alias-template] sections
+        Scenario [7]  -> ast7:  Tests duplicate [id=siptrunk, type=endpoint-template] sections
+        Scenario [8]  -> ast8:  Tests duplicate [id=siptrunk, type=identify-template] sections
+        Scenario [9]  -> ast9:  Tests duplicate [id=siptrunk, type=registration-template] sections
+        Scenario [10] -> ast10: Tests duplicate [id=siptrunk, type=system-template] sections
+        Scenario [11] -> ast11: Tests duplicate [id=siptrunk, type=transport-template] sections
+
+properties:
+    minversion: '13.4.0'
+    dependencies:
+        - asterisk: 'res_pjsip'
+        - python: 'autobahn.websocket'
+        - python: 'starpy'
+        - python: 'twisted'
+        - sipp:
+            version: 'v3.0'
+    tags:
+        - pjsip
+    issues:
+        - jira: 'ASTERISK-24996'
+
+test-modules:
+    add-test-to-search-path: 'True'
+    test-object:
+        config-section: 'test-object-config'
+        typename: 'test_case.TestCaseModule'
+    modules:
+        -
+            config-section: 'duplicate-sections'
+            typename: 'duplicate_sections.DuplicateSectionsTestHarness'
+
+test-object-config:
+    asterisk-instances: 11
+    connect-ami: 'True'
+
+duplicate-sections:
+    cli_command: 'module show like res_pjsip.so'
+    re_query: '0\smodules\sloaded'
\ No newline at end of file
diff --git a/tests/channels/pjsip/configuration/happy_config/configs/ast1/pjsip.conf b/tests/channels/pjsip/configuration/happy_config/configs/ast1/pjsip.conf
new file mode 100644
index 0000000..de1717b
--- /dev/null
+++ b/tests/channels/pjsip/configuration/happy_config/configs/ast1/pjsip.conf
@@ -0,0 +1,117 @@
+[global]
+type=global
+debug=yes
+
+[acl-template](!)
+type=acl
+contactdeny=0.0.0.0/0.0.0.0
+
+[aor-template](!)
+type=aor
+default_expiration=240
+max_contacts=5
+minimum_expiration=240
+maximum_expiration=3600
+qualify_frequency=900
+
+[auth-template](!)
+type=auth
+auth_type=userpass
+realm=asterisk
+
+[contact-template](!)
+type=contact
+qualify_frequency=0
+
+[domain-alias-template](!)
+type=domain_alias
+
+[endpoint-template](!)
+type=endpoint
+transport=trans
+disallow=all
+allow=ulaw
+allow_subscribe=yes
+allow_transfer=yes
+callerid=uut_callerid_name <uut_callerid_num>
+callerid_privacy=allowed
+connected_line_method=invite
+context=local
+device_state_busy_at=0
+direct_media=no
+fax_detect=no
+force_rport=yes
+from_domain=
+from_user=
+rewrite_contact=no
+t38_udptl=no
+t38_udptl_ec=none
+t38_udptl_ipv6=no
+t38_udptl_maxdatagram=0
+t38_udptl_nat=no
+trust_id_inbound=no
+trust_id_outbound=no
+
+[identify-template](!)
+type=identify
+
+[registration-template](!)
+type=registration
+auth_rejection_permanent=no
+expiration=3600
+forbidden_retry_interval=0
+max_retries=10
+outbound_proxy=
+retry_interval=60
+
+[system-template](!)
+type=system
+
+[transport-template](!)
+type=transport
+protocol=udp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](acl-template)
+contactpermit=127.0.0.1
+
+[siptrunk](aor-template)
+contact=siptrunk
+mailboxes=4000 at default
+
+[siptrunk](auth-template)
+username=foo
+password=bar
+
+[siptrunk](contact-template)
+contact=sip:siptrunk at 127.0.0.1:5062
+
+[siptrunk](domain-alias-template)
+domain=foo.com
+
+[siptrunk](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
+
+[siptrunk](identify-template)
+endpoint=siptrunk
+match=127.0.0.1
+
+[siptrunk](registration-template)
+client_uri=sip:siptrunk at 127.0.0.1:5061
+server_uri=siptrunk
+contact_user=siptrunk
+outbound_auth=siptrunk
+transport=siptrunk
+
+[siptrunk](system-template)
+timer_t1=500
+timer_b=32000
+compact_headers=no
+
+[siptrunk](transport-template)
+bind=127.0.0.1:5061
+
diff --git a/tests/channels/pjsip/configuration/happy_config/happy_config.py b/tests/channels/pjsip/configuration/happy_config/happy_config.py
new file mode 100755
index 0000000..320cb9b
--- /dev/null
+++ b/tests/channels/pjsip/configuration/happy_config/happy_config.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+"""
+Copyright (C) 2015, Digium, Inc.
+Ashley Sanders <asanders at digium.com>
+
+This program is free software, distributed under the terms of
+the GNU General Public License Version 2.
+"""
+
+import sys
+
+sys.path.append("lib/python")
+sys.path.append("tests/channels/pjsip/configuration")
+
+from test_harness import TestHarness
+
+
+class HappyConfigTestHarness(TestHarness):
+    """The test harness for the duplicate sections test."""
+
+    def __init__(self, config, test_object):
+        """Constructor.
+
+        Keyword Arguments:
+        config                 -- The YAML configuration for this test.
+        test_object            -- The TestCaseModule instance for this test.
+        """
+
+        super(HappyConfigTestHarness, self).__init__(config, test_object)
diff --git a/tests/channels/pjsip/configuration/happy_config/test-config.yaml b/tests/channels/pjsip/configuration/happy_config/test-config.yaml
new file mode 100644
index 0000000..f34be26
--- /dev/null
+++ b/tests/channels/pjsip/configuration/happy_config/test-config.yaml
@@ -0,0 +1,39 @@
+testinfo:
+    summary: |
+        Ensures Asterisk does not reject a correct pjsip configuration.
+    description: |
+        This test uses a pjsip.conf that represents the unique sections from
+        the base configuration for the [duplicate_sections] test, to ensure
+        Asterisk does not misidentify and reject a correct configuration.
+
+properties:
+    minversion: '13.4.0'
+    dependencies:
+        - asterisk: 'res_pjsip'
+        - python: 'autobahn.websocket'
+        - python: 'starpy'
+        - python: 'twisted'
+        - sipp:
+            version: 'v3.0'
+    tags:
+        - pjsip
+    issues:
+        - jira: 'ASTERISK-24996'
+
+test-modules:
+    add-test-to-search-path: 'True'
+    test-object:
+        config-section: 'test-object-config'
+        typename: 'test_case.TestCaseModule'
+    modules:
+        -
+            config-section: 'happy-config'
+            typename: 'happy_config.HappyConfigTestHarness'
+
+test-object-config:
+    asterisk-instances: 1
+    connect-ami: 'True'
+
+happy-config:
+    cli_command: 'module show like res_pjsip.so'
+    re_query: 'res_pjsip\.so[^\n]+\n[1-9][0-9]*\smodules\sloaded'
\ No newline at end of file
diff --git a/tests/channels/pjsip/configuration/test_harness.py b/tests/channels/pjsip/configuration/test_harness.py
new file mode 100755
index 0000000..2ed8306
--- /dev/null
+++ b/tests/channels/pjsip/configuration/test_harness.py
@@ -0,0 +1,152 @@
+#!/usr/bin/env python
+"""
+Copyright (C) 2015, Digium, Inc.
+Ashley Sanders <asanders at digium.com>
+
+This program is free software, distributed under the terms of
+the GNU General Public License Version 2.
+"""
+
+import sys
+import logging
+
+sys.path.append("lib/python")
+sys.path.append("tests/channels/pjsip/configuration")
+
+from test_scenario import TestScenario
+
+LOGGER = logging.getLogger(__name__)
+
+
+class TestHarness(object):
+    """The test harness.
+
+    This class creates and manages the life-cycle of the the objects needed to
+    execute the test plan.
+    """
+
+    def __init__(self, config, test_object):
+        """Constructor.
+
+        Keyword Arguments:
+        config                 -- The YAML configuration for this test.
+        test_object            -- The TestCaseModule instance for this test.
+        """
+
+        LOGGER.debug('{0} Initializing test harness.'.format(self))
+
+        self.test_object = test_object
+        self.scenarios = self.__build_scenarios(config)
+
+        self.test_object.register_stop_observer(self.__on_asterisk_stop)
+        self.test_object.register_ami_observer(self.__on_ami_connect)
+
+
+    def __format__(self, format_spec):
+        """Overrides default format handling for 'self'."""
+
+        return self.__class__.__name__ + ':'
+
+    def __build_scenarios(self, config):
+        """Builds the scenarios.
+
+        Keyword Arguments:
+        config                 -- The YAML configuration for this test.
+
+        Returns:
+        A list of scenarios.
+        """
+
+        LOGGER.debug('{0} Building test scenarios.'.format(self))
+
+        if not self.__validate_config(config):
+            LOGGER.error('{0} Aborting test. Configuration contains errors.')
+            self.test_object.stop_reactor()
+
+        scenarios = list()
+        for _ in range(0, self.test_object.asterisk_instances):
+            scenario = TestScenario(config['cli_command'],
+                                    config['re_query'])
+            scenarios.append(scenario)
+        return scenarios
+
+    def __on_ami_connect(self, ami):
+        """Handler for the AMI connect event.
+
+        Keyword Arguments:
+        ami                    -- The AMI instance that raised this event.
+        """
+
+        index = ami.id
+        LOGGER.info('{0} Starting execution for scenario[{1}].'.format(self,
+                                                                       index))
+        scenario = self.scenarios[index]
+        deferred = scenario.run(self.test_object.ast[index])
+        deferred.addCallbacks(self.__on_scenario_complete)
+
+    def __on_asterisk_stop(self, result):
+        """Determines the overall pass/fail state for the test prior to
+        shutting down the reactor.
+
+        Keyword Arguments:
+        result                 -- A twisted deferred object
+
+        Returns:
+        A twisted deferred object.
+        """
+
+        LOGGER.debug('{0} Calculating test results.'.format(self))
+
+        for scenario in self.scenarios:
+            self.test_object.set_passed(scenario.passed)
+        return result
+
+    def __on_scenario_complete(self, message):
+        """Queries the scenarios to determine if the test is complete.
+
+        Keyword Arguments:
+        message                -- The event payload.
+        """
+
+        LOGGER.debug('{0} Quering test scenarios.'.format(self))
+
+        for scenario in self.scenarios:
+            if not scenario.finished:
+                return
+
+        LOGGER.debug('{0} Test case execution is complete.'.format(self))
+        self.test_object.stop_reactor()
+
+    def __validate_config(self, config):
+        """Validates the module configuration for this test.
+
+        Keyword Arguments:
+        config                 -- The YAML configuration for this test.
+
+        Returns:
+        True if the configuration is valid, False otherwise.
+        """
+
+        LOGGER.debug('{0} Validating module configuration.'.format(self))
+
+        if not config:
+            LOGGER.error('{0} No configuration provided.'.format(self))
+            return False
+
+        if 'cli_command' not in config:
+            msg = '{0} Configuration is missing required attribute \'{1}\'.'
+            LOGGER.error(msg.format(self, 'cli_command'))
+            return False
+
+        if 're_query' not in config:
+            msg = '{0} Configuration is missing required attribute \'{1}\'.'
+            LOGGER.error(msg.format(self, 're_query'))
+            return False
+
+        for key in config.keys():
+            k = key.lower()
+            if k != 'cli_command' and k != 're_query':
+                msg = '{0} Unsupported configuration attribute {1} specified.'
+                LOGGER.error(msg.format(self, key))
+                return False
+        return True
diff --git a/tests/channels/pjsip/configuration/test_scenario.py b/tests/channels/pjsip/configuration/test_scenario.py
new file mode 100755
index 0000000..c7d207b
--- /dev/null
+++ b/tests/channels/pjsip/configuration/test_scenario.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+"""
+Copyright (C) 2015, Digium, Inc.
+Ashley Sanders <asanders at digium.com>
+
+This program is free software, distributed under the terms of
+the GNU General Public License Version 2.
+"""
+
+import sys
+import logging
+import re
+
+sys.path.append("lib/python")
+sys.path.append("tests/channels/pjsip/configuration")
+
+LOGGER = logging.getLogger(__name__)
+
+
+class TestScenario(object):
+    """The test scenario.
+
+    This class is responsible for executing the test strategy and reporting
+    the test results.
+    """
+
+    def __init__(self, cli_command, re_query):
+        """Constructor.
+
+        Keyword Arguments:
+        cli_command            -- The CLI command to execute.
+        re_query               -- The regex query to use to search the output
+                                  of the CLI command.
+        """
+
+        LOGGER.debug('{0} Initializing test scenario'.format(self))
+        self.__cli_command = cli_command
+        self.__re_query = re_query
+        self.__passed = None
+
+    def __format__(self, format_spec):
+        """Overrides default format handling for 'self'."""
+
+        return self.__class__.__name__ + ':'
+
+    def __parse_cli_output(self, cli_command):
+        """Parses the CLI command output to determine if the res_pjsip.so
+        module is loaded.
+
+        Keyword Arguments:
+        cli_command            -- The AsteriskCliCommand instance containing
+                                  the output to be parsed.
+
+        Returns:
+        A twisted deferred instance.
+        """
+
+        LOGGER.debug('{0} Parsing CLI Command Output.'.format(self))
+        LOGGER.debug('{0} CLI Command: {1}'.format(self, self.__cli_command))
+        LOGGER.debug('{0} CLI Output: {1}'.format(self, cli_command.output))
+
+        query_results = re.search(self.__re_query, cli_command.output)
+        self.passed = query_results is not None
+        return cli_command
+
+    def run(self, ast):
+        """Runs the scenario.
+
+        Keyword Arguments:
+        ast                    -- The Asterisk instance for this scenario.
+
+        Returns:
+        A twisted deferred instance.
+        """
+
+        LOGGER.debug('{0} Running test scenario.'.format(self))
+
+        cli_deferred = ast.cli_exec(self.__cli_command)
+        cli_deferred.addCallbacks(self.__parse_cli_output)
+        return cli_deferred
+
+    @property
+    def finished(self):
+        """Whether or not the this scenario has finished execution.
+
+        Returns:
+        True if the scenario has finished execution, False otherwise.
+        """
+
+        return self.__passed is not None
+
+    @property
+    def passed(self):
+        """The results of the scenario.
+
+        Returns:
+        False if the scenario has not finished execution. Else, True if the
+        scenario was successful, False otherwise.
+        """
+
+        return False if not self.finished else self.__passed
+
+    @passed.setter
+    def passed(self, value):
+        """Safely set the passed variable for this scenario."""
+
+        if self.__passed is False:
+            return
+
+        self.__passed = value
+        return
diff --git a/tests/channels/pjsip/configuration/tests.yaml b/tests/channels/pjsip/configuration/tests.yaml
new file mode 100644
index 0000000..6f26d7f
--- /dev/null
+++ b/tests/channels/pjsip/configuration/tests.yaml
@@ -0,0 +1,4 @@
+# Enter tests here in the order they should be considered for execution:
+tests:
+    - test: 'duplicate_sections'
+    - test: 'happy_config'
diff --git a/tests/channels/pjsip/tests.yaml b/tests/channels/pjsip/tests.yaml
index d806233..53d7d51 100644
--- a/tests/channels/pjsip/tests.yaml
+++ b/tests/channels/pjsip/tests.yaml
@@ -1,4 +1,3 @@
-# Enter tests here in the order they should be considered for execution:
 tests:
     - test: 'handle_options_request'
     - test: 'incoming_calls_without_auth'
@@ -38,3 +37,4 @@
     - test: 'in_dialog_options'
     - dir: 'resolver'
     - test: 'forward_loop'
+    - dir: 'configuration'
\ No newline at end of file

-- 
To view, visit https://gerrit.asterisk.org/241
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I36078aae985050cff323ace3ccfd7464fe1de35f
Gerrit-PatchSet: 1
Gerrit-Project: testsuite
Gerrit-Branch: master
Gerrit-Owner: Ashley Sanders <asanders at digium.com>



More information about the asterisk-code-review mailing list