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

Ashley Sanders asteriskteam at digium.com
Tue Apr 28 00:12:58 CDT 2015


Ashley Sanders has uploaded a new change for review.

  https://gerrit.asterisk.org/267

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. Seven (7) 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 for the given object type. 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=aor] sections
Scenario [2] -> ast2: Tests duplicate [id=siptrunk, type=auth] sections
Scenario [3] -> ast3: Tests duplicate [id=siptrunk, type=contact] sections
Scenario [4] -> ast4: Tests duplicate [id=siptrunk, type=endpoint] sections
Scenario [5] -> ast5: Tests duplicate [id=siptrunk, type=identify] sections
Scenario [6] -> ast6: Tests duplicate [id=siptrunk, type=registration] sections
Scenario [7] -> ast7: Tests duplicate [id=siptrunk, type=transport] 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: I661db58e001a95b5b926f2de231d099b407ad165
---
A tests/channels/pjsip/configuration/duplicate_sections/configs/ast1/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/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
16 files changed, 1,515 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.asterisk.org:29418/testsuite refs/changes/67/267/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..f99e83f
--- /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
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+[siptrunk](aor-template)
+contact=siptrunk
+mailboxes=4000 at default
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..b81ebcf
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast2/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.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](auth-template)
+username=foo
+password=bar
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..0682ad6
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast3/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.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](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
+
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..1e763dc
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast4/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.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](endpoint-template)
+aors=siptrunk
+auth=siptrunk
+from_user=siptrunk
+outbound_auth=siptrunk
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..924ccff
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast5/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.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](identify-template)
+endpoint=siptrunk
+match=127.0.0.5
\ No newline at end of file
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..c78210d
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast6/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.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](registration-template)
+client_uri=sip:siptrunk at 127.0.0.6: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/configs/ast7/pjsip.conf b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast7/pjsip.conf
new file mode 100644
index 0000000..d0079f8
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/configs/ast7/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.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](transport-template)
+bind=127.0.0.7:5061
\ 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..19acea0
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/duplicate_sections.py
@@ -0,0 +1,40 @@
+#!/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.
+        """
+
+        # The cli options for the 'pjsip show' command
+        super(DuplicateSectionsTestHarness, self).__init__(config,
+                                                           test_object)
+
+    def load_config(self, config):
+        """Loads the module configuration.
+
+        Keyword Arguments:
+        config                 -- The YAML configuration for this test.
+        """
+
+        super(DuplicateSectionsTestHarness, self).load_config(config)
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..c2b9905
--- /dev/null
+++ b/tests/channels/pjsip/configuration/duplicate_sections/test-config.yaml
@@ -0,0 +1,71 @@
+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. Seven (7) 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=aor] sections
+        Scenario [2] -> ast2: Tests duplicate [id=siptrunk, type=auth] sections
+        Scenario [3] -> ast3: Tests duplicate [id=siptrunk, type=contact] sections
+        Scenario [4] -> ast4: Tests duplicate [id=siptrunk, type=endpoint] sections
+        Scenario [5] -> ast5: Tests duplicate [id=siptrunk, type=identify] sections
+        Scenario [6] -> ast6: Tests duplicate [id=siptrunk, type=registration] sections
+        Scenario [7] -> ast7: Tests duplicate [id=siptrunk, type=transport] 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: 7
+    connect-ami: 'True'
+
+duplicate-sections:
+    test-scenarios:
+        -
+            cli_command: 'pjsip show aors'
+            output_query: 'No\sobjects\sfound\.'
+        -
+            cli_command: 'pjsip show auths'
+            output_query: 'No\sobjects\sfound\.'
+        -
+            cli_command: 'pjsip show contacts'
+            output_query: 'No\sobjects\sfound\.'
+        -
+            cli_command: 'pjsip show endpoints'
+            output_query: 'No\sobjects\sfound\.'
+        -
+            cli_command: 'pjsip show identifies'
+            output_query: 'No\sobjects\sfound\.'
+        -
+            cli_command: 'pjsip show registrations'
+            output_query: 'No\sobjects\sfound\.'
+        -
+            cli_command: 'pjsip show transports'
+            output_query: 'No\sobjects\sfound\.'
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..8314268
--- /dev/null
+++ b/tests/channels/pjsip/configuration/happy_config/test-config.yaml
@@ -0,0 +1,41 @@
+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:
+    test-scenarios:
+        -
+            cli_command: 'module show like res_pjsip.so'
+            output_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..f26a51f
--- /dev/null
+++ b/tests/channels/pjsip/configuration/test_harness.py
@@ -0,0 +1,219 @@
+#!/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.
+        """
+
+        self.__messages = self.__initialize_messages()
+        LOGGER.debug(self.__messages['initializing_harness'])
+
+        self.test_object = test_object
+
+        self.__scenarios = self.__build_scenarios(self.__load_config(config))
+
+        self.test_object.register_stop_observer(self.__on_asterisk_stop)
+        self.test_object.register_ami_observer(self.__on_ami_connect)
+
+        return
+
+    def __format__(self, format_spec):
+        """Overrides default format handling for 'self'."""
+
+        return self.__class__.__name__ + ':'
+
+    def __build_scenarios(self, config_scenarios):
+        """Builds the scenarios.
+
+        Keyword Arguments:
+        config_scenarios       -- The test-scenarios section from the YAML
+                                  configuration.
+
+        Returns:
+        A list of scenarios.
+        """
+
+        LOGGER.debug(self.__messages['building_scenarios'])
+        scenarios = list()
+        LOGGER.info('config_scenarios=%r' % config_scenarios)
+
+        for i in range(0, self.test_object.asterisk_instances):
+            config_scenario = config_scenarios[i]
+            scenario = TestScenario(config_scenario['cli_command'],
+                                    config_scenario['output_query'],
+                                    self.__on_scenario_complete)
+            scenarios.append(scenario)
+        return scenarios
+
+    def __initialize_messages(self):
+        """Creates a dictionary of pre-formatted logger messages.
+
+        Returns:
+        A dictionary of pre-formatted logger messages.
+        """
+
+        messages = dict()
+
+        base_msg = '{0} '.format(self)
+        messages['aborting_config_error'] = base_msg + \
+            'Aborting test. Configuration contains errors.'
+        messages['calculating_results'] = base_msg + \
+            'Calculating test results.'
+        messages['building_scenarios'] = base_msg + \
+            'Building test scenarios.'
+        messages['initializing_harness'] = base_msg + \
+            'Initializing test harness.'
+        messages['loading_config'] = base_msg + \
+            'Loading module configuration.'
+        messages['missing_attribute'] = base_msg + \
+            '{0} is missing required attribute \'{1}\'.'
+        messages['missing_config'] = base_msg + \
+            'No configuration provided.'
+        messages['querying_scenarios'] = base_msg + \
+            'Querying test scenarios.'
+        messages['starting_scenario'] = base_msg + \
+            'Starting execution for scenario[{0}]'
+        messages['test_complete'] = base_msg + \
+            'Test case execution is complete.'
+        messages['unsupported_attribute'] = base_msg + \
+            'Unsupported configuration attribute \'{0}\' specified.'
+        messages['validating_config'] = base_msg + \
+            'Validating module configuration.'
+
+        return messages
+
+    def __load_config(self, config):
+        """Loads the module configuration.
+
+        Keyword Arguments:
+        config                 -- The YAML configuration for this test.
+
+        Returns a list of cli_command/output_query objects to use as test
+        conditions for running the scenario.
+        """
+
+        if not self.__validate_config(config):
+            LOGGER.error(self.__messages['aborting_config_error'])
+            self.test_object.stop_reactor()
+
+        LOGGER.debug(self.__messages['loading_config'])
+
+        return config['test-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(self.__messages['starting_scenario'].format(index))
+        scenario = self.__scenarios[index]
+        scenario.run(self.test_object.ast[index])
+        return
+
+    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(self.__messages['calculating_results'])
+        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(self.__messages['querying_scenarios'])
+
+        for scenario in self.__scenarios:
+            if not scenario.finished:
+                return
+
+        LOGGER.debug(self.__messages['test_complete'])
+        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(self.__messages['validating_config'])
+
+        if not config:
+            LOGGER.error(self.__messages['missing_config'])
+            return False
+
+        if 'test-scenarios' not in config:
+            msg = self.__messages['missing_attribute']
+            LOGGER.error(msg.format('Configuration', 'test-scenarios'))
+            return False
+
+        valid = None
+
+        for scenario in config['test-scenarios']:
+            if 'cli_command' not in scenario:
+                msg = self.__messages['missing_attribute']
+                LOGGER.error(msg.format('\'test-scenario\' attribute',
+                                        'cli_command'))
+                valid = False
+
+            if 'output_query' not in scenario:
+                msg = self.__messages['missing_attribute']
+                LOGGER.error(msg.format('\'test-scenario\' attribute',
+                                        'output_query'))
+                valid = False
+
+            for key in scenario.keys():
+                k = key.lower()
+                if k != 'cli_command' and k != 'output_query':
+                    msg = self.__messages['unsupported_attribute'].format(key)
+                    LOGGER.error(msg)
+                    valid = False
+
+        return valid if valid is not None else 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..4d67134
--- /dev/null
+++ b/tests/channels/pjsip/configuration/test_scenario.py
@@ -0,0 +1,119 @@
+#!/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, output_query, on_complete=None):
+        """Constructor.
+
+        Keyword Arguments:
+        cli_command            -- The CLI command to execute.
+        output_query           -- The regex query to use to search the output
+                                  of the CLI command.
+		on_complete            -- The callback to invoke when the scenario has
+                                  completed executing (optional) (default None).
+        """
+
+        LOGGER.debug('{0} Initializing test scenario'.format(self))
+        self.__cli_command = cli_command
+        self.__output_query = output_query
+        self.__on_complete = on_complete
+        self.__passed = None
+
+    def __format__(self, format_spec):
+        """Overrides default format handling for 'self'."""
+
+        return self.__class__.__name__ + ':'
+
+    def __parse_cli_output(self, cli):
+        """Parses the CLI command output to determine if the res_pjsip.so
+        module is loaded.
+
+        Keyword Arguments:
+        cli                    -- The AsteriskCliCommand instance containing
+                                  the CLI executed command and its output.
+
+        Returns:
+        An AsteriskCliCommand instance.
+        """
+
+        command = cli.cli_cmd
+        output = cli.output
+
+        LOGGER.debug('{0} Parsing CLI Command Output.'.format(self))
+        LOGGER.debug('{0} CLI Command: {1}'.format(self, command))
+        LOGGER.debug('{0} CLI Output: {1}'.format(self, output))
+
+        query_results = re.search(self.__output_query, output)
+        self.passed = query_results is not None
+        return cli
+
+    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.addCallback(self.__parse_cli_output)
+        if self.__on_complete is not None:
+            cli_deferred.addCallback(self.__on_complete)
+        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..b9af685 100644
--- a/tests/channels/pjsip/tests.yaml
+++ b/tests/channels/pjsip/tests.yaml
@@ -38,3 +38,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/267
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I661db58e001a95b5b926f2de231d099b407ad165
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