[asterisk-commits] mmichelson: testsuite/asterisk/trunk r4639 - in /asterisk/trunk: lib/python/a...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Jan 31 16:33:48 CST 2014
Author: mmichelson
Date: Fri Jan 31 16:33:45 2014
New Revision: 4639
URL: http://svnview.digium.com/svn/testsuite?view=rev&rev=4639
Log:
Create pluggable module for PJSUA and PJSIP subscription tests.
In order to test subscriptions, a smarter client than what is provided
by SIPp is required. Using PJSUA is a good option since it can subscribe
to presence. In order to more easily create future PJSUA tests, I created
a pluggable module that allows for PJSUA accounts, transports, and buddies
to be created via YAML configuration.
In addition to the pluggable module, three tests have been added:
presence_pidf: Tests that PIDF bodies contain information we expect
presence_xpidf: Tests that XPIDF bodies contain information we expect
mwi: Tests that MWI bodies contain information we expect.
Review: https://reviewboard.asterisk.org/r/3151
Added:
asterisk/trunk/tests/channels/pjsip/mwi/
asterisk/trunk/tests/channels/pjsip/mwi/configs/
asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/
asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/modules.conf (with props)
asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/pjsip.conf (with props)
asterisk/trunk/tests/channels/pjsip/mwi/mwi_check.py (with props)
asterisk/trunk/tests/channels/pjsip/mwi/test-config.yaml (with props)
asterisk/trunk/tests/channels/pjsip/presence_pidf/
asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/
asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/
asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/extensions.conf (with props)
asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/modules.conf (with props)
asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/pjsip.conf (with props)
asterisk/trunk/tests/channels/pjsip/presence_pidf/state_check.py (with props)
asterisk/trunk/tests/channels/pjsip/presence_pidf/test-config.yaml (with props)
asterisk/trunk/tests/channels/pjsip/presence_xpidf/
asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/
asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/
asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/extensions.conf (with props)
asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/modules.conf (with props)
asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/pjsip.conf (with props)
asterisk/trunk/tests/channels/pjsip/presence_xpidf/state_check.py (with props)
asterisk/trunk/tests/channels/pjsip/presence_xpidf/test-config.yaml (with props)
Modified:
asterisk/trunk/lib/python/asterisk/pluggable_modules.py
asterisk/trunk/tests/channels/pjsip/tests.yaml
Modified: asterisk/trunk/lib/python/asterisk/pluggable_modules.py
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/lib/python/asterisk/pluggable_modules.py?view=diff&rev=4639&r1=4638&r2=4639
==============================================================================
--- asterisk/trunk/lib/python/asterisk/pluggable_modules.py (original)
+++ asterisk/trunk/lib/python/asterisk/pluggable_modules.py Fri Jan 31 16:33:45 2014
@@ -10,10 +10,12 @@
import sys
import logging
+import socket
sys.path.append("lib/python")
from ami import AMIEventInstance
from twisted.internet import reactor
+import pjsua as pj
LOGGER = logging.getLogger(__name__)
@@ -261,3 +263,231 @@
LOGGER.info("All channels have hungup; stopping test")
self.test_object.stop_reactor()
return (ami, event)
+
+
+class RegDetector(pj.AccountCallback):
+ """
+ Class that detects PJSUA account registration
+
+ This is a subclass of pj.AccountCallback and is set as the callback class
+ for PJSUA accounts by the pluggable module.
+
+ The only method that is overridden is the on_reg_state method, which is
+ called when the registration state of an account changes. When all
+ configured accounts have registered, then the configured callback method
+ for the test is called into.
+
+ This means that as written, all PJSUA tests require registration to be
+ performed.
+ """
+ def __init__(self, test_plugin):
+ self.test_plugin = test_plugin
+ pj.AccountCallback.__init__(self)
+
+ def on_reg_state(self):
+ """
+ Method that is called into when an account's registration state
+ changes.
+
+ If the registration status is in the 2XX range, then it means the
+ account has successfully registered with Asterisk. Once all configured
+ accounts have registered, this method will call the configured callback
+ method.
+
+ Since on_reg_state is called from PJSUA's thread, the ensuing callback
+ to the configured callback is pushed into the reactor thread.
+ """
+ status = self.account.info().reg_status
+ uri = self.account.info().uri
+
+ if status >= 200 and status < 300:
+ LOGGER.info("Detected successful registration from %s" % uri)
+ self.test_plugin.num_regs += 1
+
+ if self.test_plugin.num_regs == self.test_plugin.num_accts:
+ callback_module = __import__(self.test_plugin.callback_module)
+ callback_method = getattr(callback_module,
+ self.test_plugin.callback_method)
+ reactor.callFromThread(callback_method,
+ self.test_plugin.test_object,
+ self.test_plugin.pj_accounts)
+
+
+class PJsuaAccount(object):
+ """
+ Wrapper for pj.Account object
+
+ This object contains a reference to a pj.Account and a dictionary of the
+ account's buddies, keyed by buddy name
+ """
+ def __init__(self, account):
+ self.account = account
+ self.buddies = {}
+
+ def add_buddies(self, buddy_cfg):
+ """
+ Add configured buddies to the account.
+
+ All buddies are required to have a name and a URI set.
+ """
+ for buddy in buddy_cfg:
+ name = buddy.get('name')
+ if not name:
+ LOGGER.warning("Unable to add buddy with no name")
+ continue
+
+ uri = buddy.get('uri')
+ if not uri:
+ LOGGER.warning("Unable to add buddy %s. No URI", name)
+ continue
+
+ self.buddies[name] = self.account.add_buddy(uri)
+
+
+class PJsua(object):
+ """A class that takes care of the initialization and account creation for
+ PJSUA endpoints during a test.
+
+ This class will initiate PJLIB, create any configured accounts, and wait
+ for the accounts to register. Once registered, this will call into user
+ code so that manipulation of the endpoints may be performed.
+ """
+
+ def __init__(self, instance_config, test_object):
+ """Constructor for pluggable modules."""
+ super(PJsua, self).__init__()
+ self.test_object = test_object
+ self.test_object.register_ami_observer(self.__ami_connect)
+ self.config = instance_config
+ self.pj_transports = {}
+ self.pj_accounts = {}
+ self.lib = None
+ self.num_regs = 0
+ self.num_accts = 0
+ self.ami = None
+ self.acct_cb = RegDetector(self)
+ self.callback_module = instance_config['callback_module']
+ self.callback_method = instance_config['callback_method']
+
+ def __ami_connect(self, ami):
+ """
+ Handler for when AMI has started.
+
+ We use AMI connection as the signal to start creating PJSUA accounts
+ and starting PJLIB.
+ """
+ self.ami = ami
+ self.lib = pj.Lib()
+ try:
+ self.lib.init()
+ self.__create_transports()
+ self.lib.set_null_snd_dev()
+ self.__create_accounts()
+ self.lib.start()
+ except pj.Error, exception:
+ LOGGER.error("Exception: " + str(exception))
+ self.lib.destroy()
+ self.lib = None
+ self.test_object.stop_reactor()
+
+ def __create_transport(self, cfg):
+ """Create a PJSUA transport from a transport configuration."""
+ def __to_pjprotocol(prot_str, is_v6):
+ """
+ Translate a string protocol to an enumerated type for PJSUA.
+
+ PJSUA's enumerations require both the transport protocol to be used
+ and whether IPv6 is being used.
+ """
+ if prot_str == 'udp':
+ if is_v6:
+ return pj.TransportType.UDP_IPV6
+ else:
+ return pj.TransportType.UDP
+ elif prot_str == 'tcp':
+ if is_v6:
+ return pj.TransportType.TCP_IPV6
+ else:
+ return pj.TransportType.TCP
+ elif prot_str == 'tls':
+ if is_v6:
+ LOGGER.error("PJSUA python bindings do not support IPv6"
+ "with TLS")
+ self.test_object.stop_reactor()
+ else:
+ return pj.TransportType.TLS
+ else:
+ return pj.TransportType.UNSPECIFIED
+
+ protocol = (cfg.get('protocol', 'udp')).lower()
+ bind = cfg.get('bind', '127.0.0.1')
+ bindport = cfg.get('bindport', '5060')
+ public_addr = cfg.get('public_addr', '')
+ is_v6 = False
+
+ try:
+ socket.inet_pton(socket.AF_INET6, bind)
+ is_v6 = True
+ except socket.error:
+ # Catching an exception just means the address is not IPv6
+ pass
+
+ pj_protocol = __to_pjprotocol(protocol, is_v6)
+ LOGGER.info("Creating transport config %s:%s" % (bind, bindport))
+ transport_cfg = pj.TransportConfig(int(bindport), bind, public_addr)
+ return self.lib.create_transport(pj_protocol, transport_cfg)
+
+ def __create_transports(self):
+ """
+ Create all configured transports
+
+ If no transports are configured, then a single transport, called
+ "default" will be created, using address 127.0.0.1, UDP port 5060.
+ """
+ if not self.config.get('transports'):
+ cfg = {
+ 'name': 'default',
+ }
+ self.__create_transport(cfg)
+ return
+
+ for cfg in self.config['transports']:
+ if not cfg.get('name'):
+ LOGGER.error("No transport name specified")
+ self.test_object.stop_reactor()
+ self.pj_transports[cfg['name']] = self.__create_transport(cfg)
+
+ def __create_account(self, acct_cfg):
+ """Create a PJSuaAccount from configuration"""
+ name = acct_cfg['name']
+ username = acct_cfg.get('username', name)
+ domain = acct_cfg.get('domain', '127.0.0.1')
+ password = acct_cfg.get('password', '')
+
+ pj_acct_cfg = pj.AccountConfig(domain, username, password, name)
+
+ LOGGER.info("Creating PJSUA account %s@%s" % (username, domain))
+ account = PJsuaAccount(self.lib.create_account(pj_acct_cfg, False,
+ self.acct_cb))
+ account.add_buddies(acct_cfg.get('buddies', []))
+ return account
+
+ def __create_accounts(self):
+ """
+ Create all configured PJSUA accounts.
+
+ All accounts must have a name specified. All other parameters will have
+ suitable defaults provided if not present. See the sample yaml file for
+ default values.
+ """
+ if not self.config.get('accounts'):
+ LOGGER.error("No accounts configured")
+ self.test_object.stop_reactor()
+
+ self.num_accts = len(self.config['accounts'])
+ for acct in self.config['accounts']:
+ name = acct.get('name')
+ if not name:
+ LOGGER.error("Account configuration has no name")
+ self.test_object.stop_reactor()
+ self.pj_accounts[name] = self.__create_account(acct)
Added: asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/modules.conf
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/modules.conf?view=auto&rev=4639
==============================================================================
--- asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/modules.conf (added)
+++ asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/modules.conf Fri Jan 31 16:33:45 2014
@@ -1,0 +1,9 @@
+[modules]
+autoload=yes
+
+noload => chan_alsa.so
+noload => chan_oss.so
+noload => chan_console.so
+noload => chan_sip.so
+
+noload => app_voicemail.so
Propchange: asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/modules.conf
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/modules.conf
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/modules.conf
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/pjsip.conf
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/pjsip.conf?view=auto&rev=4639
==============================================================================
--- asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/pjsip.conf (added)
+++ asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/pjsip.conf Fri Jan 31 16:33:45 2014
@@ -1,0 +1,15 @@
+[local-transport]
+type=transport
+bind=127.0.0.1
+protocol=udp
+
+[alice]
+type=endpoint
+allow=g722,ulaw,alaw
+context=default
+aors=alice
+mailboxes=alice
+
+[alice]
+type=aor
+max_contacts=5
Propchange: asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/pjsip.conf
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/pjsip.conf
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: asterisk/trunk/tests/channels/pjsip/mwi/configs/ast1/pjsip.conf
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: asterisk/trunk/tests/channels/pjsip/mwi/mwi_check.py
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/mwi/mwi_check.py?view=auto&rev=4639
==============================================================================
--- asterisk/trunk/tests/channels/pjsip/mwi/mwi_check.py (added)
+++ asterisk/trunk/tests/channels/pjsip/mwi/mwi_check.py Fri Jan 31 16:33:45 2014
@@ -1,0 +1,87 @@
+import logging
+import pjsua as pj
+
+LOGGER = logging.getLogger(__name__)
+
+
+class AliceCallback(pj.AccountCallback):
+ mwis = [
+ {'new': '2', 'old': '0'},
+ {'new': '1', 'old': '1'},
+ {'new': '0', 'old': '2'},
+ ]
+ results = [
+ {'waiting': 'yes', 'msgs': '2/0'},
+ {'waiting': 'yes', 'msgs': '1/1'},
+ {'waiting': 'no', 'msgs': '0/2'},
+ {'waiting': 'no', 'msgs': '0/0'},
+ ]
+
+ def __init__(self, alice, test_object):
+ pj.AccountCallback.__init__(self, alice)
+ self.pos = 0
+ self.result_pos = 0
+ self.test_object = test_object
+ self.ami = self.test_object.ami[0]
+ self.deleted = False
+
+ def check_mwi(self, body):
+ waiting = "Messages-Waiting: %s\r\n" % \
+ self.results[self.result_pos]['waiting']
+
+ msgs = "Voice-Message: %s (0/0)\r\n" % \
+ self.results[self.result_pos]['msgs']
+
+ if not waiting in body:
+ LOGGER.error("Could not find pattern %s in MWI body %s" %
+ (waiting, body))
+ self.test_object.set_passed(False)
+ self.test_object.stop_reactor()
+ if not msgs in body:
+ LOGGER.error("Could not find pattern %s in MWI body %s" %
+ (msgs, body))
+ self.test_object.set_passed(False)
+ self.test_object.stop_reactor()
+
+ self.result_pos += 1
+
+ def on_mwi_info(self, body):
+ self.check_mwi(body)
+ self.pos += 1
+ if (self.pos < len(self.mwis)):
+ self.send_mwi()
+ return
+
+ if (self.deleted):
+ self.test_object.set_passed(True)
+ self.test_object.stop_reactor()
+ else:
+ self.delete_mwi()
+ self.deleted = True
+
+ def send_mwi(self):
+ LOGGER.info("Sending MWI update. new: %s, old %s" %
+ (self.mwis[self.pos]['new'],
+ self.mwis[self.pos]['old']))
+ message = {
+ 'Action': 'MWIUpdate',
+ 'Mailbox': 'alice',
+ 'NewMessages': self.mwis[self.pos]['new'],
+ 'OldMessages': self.mwis[self.pos]['old']
+ }
+ self.ami.sendMessage(message)
+
+ def delete_mwi(self):
+ LOGGER.info("Deleting Mailbox")
+ message = {
+ 'Action': 'MWIDelete',
+ 'Mailbox': 'alice',
+ }
+ self.ami.sendMessage(message)
+
+
+def mwi_callback(test_object, accounts):
+ alice = accounts.get('alice')
+ cb = AliceCallback(alice, test_object)
+ alice.account.set_callback(cb)
+ cb.send_mwi()
Propchange: asterisk/trunk/tests/channels/pjsip/mwi/mwi_check.py
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: asterisk/trunk/tests/channels/pjsip/mwi/mwi_check.py
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: asterisk/trunk/tests/channels/pjsip/mwi/mwi_check.py
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: asterisk/trunk/tests/channels/pjsip/mwi/test-config.yaml
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/mwi/test-config.yaml?view=auto&rev=4639
==============================================================================
--- asterisk/trunk/tests/channels/pjsip/mwi/test-config.yaml (added)
+++ asterisk/trunk/tests/channels/pjsip/mwi/test-config.yaml Fri Jan 31 16:33:45 2014
@@ -1,0 +1,46 @@
+testinfo:
+ summary: 'Ensures MWI bodies consist of accurate information'
+ description: |
+ "Unsolicited MWI notifications are sent to an endpoint as mailbox state updates. PJSUA
+ accounts notify us when an MWI notification arrives. We check the body of these MWI
+ notifications to ensure that they contain the data we expect them to."
+
+
+properties:
+ minversion: '12.0.0'
+ dependencies:
+ - python: 'twisted'
+ - python: 'starpy'
+ - python: 'pjsua'
+ - asterisk: 'res_pjsip'
+ - asterisk: 'res_pjsip_mwi'
+ tags:
+ - pjsip
+
+test-modules:
+ add-test-to-search-path: 'True'
+ test-object:
+ config-section: test-case-config
+ typename: 'test_case.TestCaseModule'
+ modules:
+ -
+ config-section: 'pjsua-config'
+ typename: 'pluggable_modules.PJsua'
+
+test-case-config:
+ connect-ami: 'True'
+
+pjsua-config:
+ callback_module: 'mwi_check'
+ callback_method: 'mwi_callback'
+ transports:
+ -
+ name: 'local-ipv4'
+ bind: '127.0.0.1'
+ bindport: '5061'
+ accounts:
+ -
+ name: 'alice'
+ username: 'alice'
+ password: 'alice'
+ domain: '127.0.0.1'
Propchange: asterisk/trunk/tests/channels/pjsip/mwi/test-config.yaml
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: asterisk/trunk/tests/channels/pjsip/mwi/test-config.yaml
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: asterisk/trunk/tests/channels/pjsip/mwi/test-config.yaml
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/extensions.conf
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/extensions.conf?view=auto&rev=4639
==============================================================================
--- asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/extensions.conf (added)
+++ asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/extensions.conf Fri Jan 31 16:33:45 2014
@@ -1,0 +1,3 @@
+[default]
+
+exten => bob,hint,Custom:bob
Propchange: asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/extensions.conf
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/extensions.conf
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/extensions.conf
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/modules.conf
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/modules.conf?view=auto&rev=4639
==============================================================================
--- asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/modules.conf (added)
+++ asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/modules.conf Fri Jan 31 16:33:45 2014
@@ -1,0 +1,9 @@
+[modules]
+autoload=yes
+
+noload => chan_alsa.so
+noload => chan_oss.so
+noload => chan_console.so
+noload => chan_sip.so
+
+noload => res_pjsip_xpidf_body_generator.so
Propchange: asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/modules.conf
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/modules.conf
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/modules.conf
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/pjsip.conf
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/pjsip.conf?view=auto&rev=4639
==============================================================================
--- asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/pjsip.conf (added)
+++ asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/pjsip.conf Fri Jan 31 16:33:45 2014
@@ -1,0 +1,14 @@
+[local-transport]
+type=transport
+bind=127.0.0.1
+protocol=udp
+
+[alice]
+type=endpoint
+allow=g722,ulaw,alaw
+context=default
+aors=alice
+
+[alice]
+type=aor
+max_contacts=5
Propchange: asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/pjsip.conf
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/pjsip.conf
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: asterisk/trunk/tests/channels/pjsip/presence_pidf/configs/ast1/pjsip.conf
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: asterisk/trunk/tests/channels/pjsip/presence_pidf/state_check.py
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/presence_pidf/state_check.py?view=auto&rev=4639
==============================================================================
--- asterisk/trunk/tests/channels/pjsip/presence_pidf/state_check.py (added)
+++ asterisk/trunk/tests/channels/pjsip/presence_pidf/state_check.py Fri Jan 31 16:33:45 2014
@@ -1,0 +1,69 @@
+#!/usr/bin/env python
+
+import logging
+import pjsua as pj
+
+LOGGER = logging.getLogger(__name__)
+
+states = [
+ ('INUSE', 2, "On the phone"),
+ ('ONHOLD', 2, "On hold"),
+ ('BUSY', 2, "On the phone"),
+ ('RINGING', 2, "Ringing"),
+ ('UNAVAILABLE', 2, "Unavailable"),
+ ('NOT_INUSE', 1, "Ready"),
+ ('', 1, "Ready") # Final state upon subscription teardown
+]
+
+
+class BobCallback(pj.BuddyCallback):
+ def __init__(self, bob, test_object):
+ pj.BuddyCallback.__init__(self, bob)
+ self.pos = 0
+ self.test_object = test_object
+ self.ami = self.test_object.ami[0]
+ self.check_status = False
+
+ def on_state(self):
+ info = self.buddy.info()
+
+ LOGGER.info("Bob status to folow")
+ LOGGER.info("Online status: %d" % info.online_status)
+ LOGGER.info("Online text: %s" % info.online_text)
+ LOGGER.info("Activity: %d" % info.activity)
+ LOGGER.info("Sub state: %d" % info.sub_state)
+
+ # We don't care about the buddy state until the subscription is active.
+ if info.sub_state < pj.SubscriptionState.ACTIVE:
+ return
+
+ if self.check_status:
+ if info.online_status != states[self.pos][1]:
+ LOGGER.error("Unexpected state %d. Expected %d" %
+ (info.online_status, states[self.pos][1]))
+ self.test_object.set_passed(False)
+ self.test_object.stop_reactor(False)
+ if info.online_text != states[self.pos][2]:
+ LOGGER.error("Unexpected text %s. Expected %s" %
+ (info.online_text, states[self.pos][2]))
+ self.test_object.set_passed(False)
+ self.test_object.stop_reactor(False)
+ self.pos += 1
+ if (self.pos >= len(states)):
+ self.test_object.set_passed(True)
+ self.test_object.stop_reactor()
+
+ if self.pos < len(states) and states[self.pos][0]:
+ LOGGER.info("Setting device state to %s" % states[self.pos][0])
+ self.check_status = True
+ self.ami.setVar(channel="", variable="DEVICE_STATE(Custom:bob)",
+ value=states[self.pos][0])
+ else:
+ self.buddy.unsubscribe()
+
+
+def buddy_subscribe(test_object, accounts):
+ alice = accounts.get('alice')
+ bob = alice.buddies.get('bob')
+ bob.set_callback(BobCallback(bob, test_object))
+ bob.subscribe()
Propchange: asterisk/trunk/tests/channels/pjsip/presence_pidf/state_check.py
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: asterisk/trunk/tests/channels/pjsip/presence_pidf/state_check.py
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: asterisk/trunk/tests/channels/pjsip/presence_pidf/state_check.py
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: asterisk/trunk/tests/channels/pjsip/presence_pidf/test-config.yaml
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/presence_pidf/test-config.yaml?view=auto&rev=4639
==============================================================================
--- asterisk/trunk/tests/channels/pjsip/presence_pidf/test-config.yaml (added)
+++ asterisk/trunk/tests/channels/pjsip/presence_pidf/test-config.yaml Fri Jan 31 16:33:45 2014
@@ -1,0 +1,50 @@
+testinfo:
+ summary: 'Test PJSIP PIDF presence notification'
+ description: |
+ 'This test creates a PJSUA account, "alice", that subscribes to
+ buddy "bob". Asterisk changes the state of Bob to device states that
+ map to each of the extension states. We then ensure that PJSUA was
+ given the state we expected for each state change.'
+
+properties:
+ minversion: '12.1.0'
+ dependencies:
+ - python: 'twisted'
+ - python: 'starpy'
+ - python: 'pjsua'
+ - asterisk: 'res_pjsip'
+ - asterisk: 'res_pjsip_exten_state'
+ tags:
+ - pjsip
+
+test-modules:
+ add-test-to-search-path: 'True'
+ test-object:
+ config-section: test-case-config
+ typename: 'test_case.TestCaseModule'
+ modules:
+ -
+ config-section: 'pjsua-config'
+ typename: 'pluggable_modules.PJsua'
+
+test-case-config:
+ connect-ami: 'True'
+
+pjsua-config:
+ callback_module: 'state_check'
+ callback_method: 'buddy_subscribe'
+ transports:
+ -
+ name: 'local-ipv4'
+ bind: '127.0.0.1'
+ bindport: '5061'
+ accounts:
+ -
+ name: 'alice'
+ username: 'alice'
+ password: 'alice'
+ domain: '127.0.0.1'
+ buddies:
+ -
+ name: 'bob'
+ uri: 'sip:bob at 127.0.0.1'
Propchange: asterisk/trunk/tests/channels/pjsip/presence_pidf/test-config.yaml
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: asterisk/trunk/tests/channels/pjsip/presence_pidf/test-config.yaml
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: asterisk/trunk/tests/channels/pjsip/presence_pidf/test-config.yaml
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/extensions.conf
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/extensions.conf?view=auto&rev=4639
==============================================================================
--- asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/extensions.conf (added)
+++ asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/extensions.conf Fri Jan 31 16:33:45 2014
@@ -1,0 +1,3 @@
+[default]
+
+exten => bob,hint,Custom:bob
Propchange: asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/extensions.conf
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/extensions.conf
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/extensions.conf
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/modules.conf
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/modules.conf?view=auto&rev=4639
==============================================================================
--- asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/modules.conf (added)
+++ asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/modules.conf Fri Jan 31 16:33:45 2014
@@ -1,0 +1,9 @@
+[modules]
+autoload=yes
+
+noload => chan_alsa.so
+noload => chan_oss.so
+noload => chan_console.so
+noload => chan_sip.so
+
+noload => res_pjsip_pidf_body_generator.so
Propchange: asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/modules.conf
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/modules.conf
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/modules.conf
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/pjsip.conf
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/pjsip.conf?view=auto&rev=4639
==============================================================================
--- asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/pjsip.conf (added)
+++ asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/pjsip.conf Fri Jan 31 16:33:45 2014
@@ -1,0 +1,14 @@
+[local-transport]
+type=transport
+bind=127.0.0.1
+protocol=udp
+
+[alice]
+type=endpoint
+allow=g722,ulaw,alaw
+context=default
+aors=alice
+
+[alice]
+type=aor
+max_contacts=5
Propchange: asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/pjsip.conf
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/pjsip.conf
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: asterisk/trunk/tests/channels/pjsip/presence_xpidf/configs/ast1/pjsip.conf
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: asterisk/trunk/tests/channels/pjsip/presence_xpidf/state_check.py
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/presence_xpidf/state_check.py?view=auto&rev=4639
==============================================================================
--- asterisk/trunk/tests/channels/pjsip/presence_xpidf/state_check.py (added)
+++ asterisk/trunk/tests/channels/pjsip/presence_xpidf/state_check.py Fri Jan 31 16:33:45 2014
@@ -1,0 +1,69 @@
+#!/usr/bin/env python
+
+import logging
+import pjsua as pj
+
+LOGGER = logging.getLogger(__name__)
+
+states = [
+ ('INUSE', 2, "Offline"),
+ ('ONHOLD', 2, "Offline"),
+ ('BUSY', 2, "Offline"),
+ ('RINGING', 2, "Offline"),
+ ('UNAVAILABLE', 2, "Offline"),
+ ('NOT_INUSE', 1, "Online"),
+ ('', 1, "Online") # Final state upon subscription teardown
+]
+
+
+class BobCallback(pj.BuddyCallback):
+ def __init__(self, bob, test_object):
+ pj.BuddyCallback.__init__(self, bob)
+ self.pos = 0
+ self.test_object = test_object
+ self.ami = self.test_object.ami[0]
+ self.check_status = False
+
+ def on_state(self):
+ info = self.buddy.info()
+
+ LOGGER.info("Bob status to folow")
+ LOGGER.info("Online status: %d" % info.online_status)
+ LOGGER.info("Online text: %s" % info.online_text)
+ LOGGER.info("Activity: %d" % info.activity)
+ LOGGER.info("Sub state: %d" % info.sub_state)
+
+ # We don't care about the buddy state until the subscription is active.
+ if info.sub_state < pj.SubscriptionState.ACTIVE:
+ return
+
+ if self.check_status:
+ if info.online_status != states[self.pos][1]:
+ LOGGER.error("Unexpected state %d. Expected %d" %
+ (info.online_status, states[self.pos][1]))
+ self.test_object.set_passed(False)
+ self.test_object.stop_reactor(False)
+ if info.online_text != states[self.pos][2]:
+ LOGGER.error("Unexpected text %s. Expected %s" %
+ (info.online_text, states[self.pos][2]))
+ self.test_object.set_passed(False)
+ self.test_object.stop_reactor()
+ self.pos += 1
+ if (self.pos >= len(states)):
+ self.test_object.set_passed(True)
+ self.test_object.stop_reactor()
+
+ if self.pos < len(states) and states[self.pos][0]:
+ LOGGER.info("Setting device state to %s" % states[self.pos][0])
+ self.check_status = True
+ self.ami.setVar(channel="", variable="DEVICE_STATE(Custom:bob)",
+ value=states[self.pos][0])
+ else:
+ self.buddy.unsubscribe()
+
+
+def buddy_subscribe(test_object, accounts):
+ alice = accounts.get('alice')
+ bob = alice.buddies.get('bob')
+ bob.set_callback(BobCallback(bob, test_object))
+ bob.subscribe()
Propchange: asterisk/trunk/tests/channels/pjsip/presence_xpidf/state_check.py
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: asterisk/trunk/tests/channels/pjsip/presence_xpidf/state_check.py
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: asterisk/trunk/tests/channels/pjsip/presence_xpidf/state_check.py
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: asterisk/trunk/tests/channels/pjsip/presence_xpidf/test-config.yaml
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/pjsip/presence_xpidf/test-config.yaml?view=auto&rev=4639
==============================================================================
--- asterisk/trunk/tests/channels/pjsip/presence_xpidf/test-config.yaml (added)
+++ asterisk/trunk/tests/channels/pjsip/presence_xpidf/test-config.yaml Fri Jan 31 16:33:45 2014
@@ -1,0 +1,49 @@
+testinfo:
+ summary: 'Test PJSIP XPIDF presence notification'
+ description: |
+ 'This test creates a PJSUA account, "alice", that subscribes to
+ buddy "bob". Asterisk changes the state of Bob to device states that
+ map to each of the extension states. We then ensure that PJSUA was
+ given the state we expected for each state change.'
+
+properties:
+ minversion: '12.1.0'
+ dependencies:
+ - python: 'twisted'
+ - python: 'starpy'
+ - python: 'pjsua'
+ - asterisk: 'res_pjsip'
+ tags:
+ - pjsip
+
+test-modules:
+ add-test-to-search-path: 'True'
+ test-object:
+ config-section: test-case-config
+ typename: 'test_case.TestCaseModule'
+ modules:
+ -
+ config-section: 'pjsua-config'
+ typename: 'pluggable_modules.PJsua'
+
+test-case-config:
+ connect-ami: 'True'
+
+pjsua-config:
+ callback_module: 'state_check'
+ callback_method: 'buddy_subscribe'
+ transports:
+ -
+ name: 'local-ipv4'
+ bind: '127.0.0.1'
+ bindport: '5061'
+ accounts:
+ -
+ name: 'alice'
+ username: 'alice'
+ password: 'alice'
+ domain: '127.0.0.1'
+ buddies:
+ -
+ name: 'bob'
+ uri: 'sip:bob at 127.0.0.1'
Propchange: asterisk/trunk/tests/channels/pjsip/presence_xpidf/test-config.yaml
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: asterisk/trunk/tests/channels/pjsip/presence_xpidf/test-config.yaml
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: asterisk/trunk/tests/channels/pjsip/presence_xpidf/test-config.yaml
[... 16 lines stripped ...]
More information about the asterisk-commits
mailing list