<p>Corey Farrell has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/9314">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Begin work on python3 compatability.<br><br>* Use explicit relative import syntax.<br>* Correct syntax for print and except.<br>* Fix incorrect usage of IOError in astcdr.py - IOError is not a tuple.<br>* Use items, values instead of iteritems, itervalues.<br>* Use OrderedDict from collections if available (python 2.7+).<br>* Do not unpack tuples from argument list, save tuple to variable then<br> unpack within code.<br>* Use exception handler to import Python3 version of urlencode if the<br> Python2 version fails to import.<br>* Remove unused import unittest from opensslversion.<br>* Move executable tests to separate files to resolve issues with<br> relative imports:<br> - buildoptions<br> - cdr<br> - cel<br> - channel_test_condition<br> - config<br> - lock_test_condition<br> - sip_dialog_test_condition (disabled)<br> - sippversion<br>* Modify utils_socket test to use new harness_shared module.<br>* Remove unused executable flag and shebang from phones.py.<br>* Update self_test script to run tests from new location.<br>* Remove ability to use config.py to display a config file.<br>* Allow PYTHON environmental variable to tell run-local to use a<br> specific python binary.<br>* Execute test_runner.py using python -m syntax. This avoids conflicts<br> between needing to use relative imports for modules but not being<br> allowed to use them in executable scripts.<br>* Encode self.realbase for use with md5 function.<br>* Remove executable flag and shebang from test_runner.py. Remove<br> redundant appending of sys.path.<br>* Modify output for running test and status to print the name of the<br> test instead of the command used to run the test.<br>* Use key= sorter argument to compare sizes of tmp filesystems. This<br> may cause us to use /var/tmp instead of /tmp even if /var/tmp has only<br> a few kilobytes more space but python3 does not support cmp= argument<br> to sorter.<br>* Decode binary to utf-8<br> - CLI output<br> - runtest.py subprocess output<br> - XML printed to stdout<br> - SyncAMI data<br> - SIPp runtime and version output<br>* Update test_runner.load_and_parse_module to check for the module in<br> lib/python/asterisk, make required adjustments if found.<br>* Update __strip_illegal_xml_chars to work with unicode version of<br> str.translate which does not support second argument.<br>* Update import statements from all *.py modules within tests/ to use<br> absolute names for asterisk modules. This is required for python2 to<br> continue functioning with the new way that test_runner must be executed.<br> No attempt has been made to fix python3 compatibility issues in these<br> modules.<br><br>Some tests may pass using python3. Doing so requires using an updated<br>starpy and no python sources within tests/ have been updated. Unit<br>tests from lib/python can be run against python2 and python3 using<br>./self_test.<br><br>The goal of this is for all tests to continue functioning using python2.<br>Some tests may work under python3 but individual tests will need to be<br>addressed separately. For tests which do not contain a run-test script<br>the version of python used to execute ./runtests.py will be used:<br>./runtests.py -t tests/manager/originate<br>python2 ./runtests.py -t tests/manager/originate<br>python3 ./runtests.py -t tests/manager/originate<br><br>These commands will be python, python2 and python3 respectively. The<br>first example where no interpreter is specified uses the shebang from<br>./runtests.py. The interpreter used by ./run-local can be controlled<br>by setting PYTHON environmental variable:<br>PYTHON=python3 ./run-local run -t tests/manager/originate<br><br>Change-Id: If76c2d3e11e4ab4552d0df7841287c8bb2de7918<br>---<br>M lib/python/asterisk/ami.py<br>M lib/python/asterisk/apptest.py<br>M lib/python/asterisk/ari.py<br>M lib/python/asterisk/astconfigparser.py<br>M lib/python/asterisk/astcsv.py<br>M lib/python/asterisk/astdicts.py<br>M lib/python/asterisk/asterisk.py<br>M lib/python/asterisk/bridge_test_case.py<br>M lib/python/asterisk/buildoptions.py<br>M lib/python/asterisk/cdr.py<br>M lib/python/asterisk/cel.py<br>M lib/python/asterisk/channel_test_condition.py<br>M lib/python/asterisk/confbridge.py<br>M lib/python/asterisk/config.py<br>M lib/python/asterisk/fd_test_condition.py<br>M lib/python/asterisk/lock_test_condition.py<br>M lib/python/asterisk/matcher.py<br>M lib/python/asterisk/matcher_listener.py<br>M lib/python/asterisk/opensslversion.py<br>M lib/python/asterisk/originate.py<br>M lib/python/asterisk/pcap.py<br>M lib/python/asterisk/phones.py<br>M lib/python/asterisk/pjsua_mod.py<br>M lib/python/asterisk/pluggable_modules.py<br>M lib/python/asterisk/pluggable_registry.py<br>M lib/python/asterisk/realtime_converter.py<br>M lib/python/asterisk/realtime_odbc_module.py<br>M lib/python/asterisk/realtime_test_module.py<br>A lib/python/asterisk/self_test/harness_shared.py<br>A lib/python/asterisk/self_test/locks-backtrace.txt<br>A lib/python/asterisk/self_test/locks-fail.txt<br>A lib/python/asterisk/self_test/locks-large-multiple-object.txt<br>A lib/python/asterisk/self_test/locks-multiple-objects-no-backtrace.txt<br>A lib/python/asterisk/self_test/locks-pass.txt<br>A lib/python/asterisk/self_test/locks-single-object-no-held-info.txt<br>A lib/python/asterisk/self_test/locks-single-object.txt<br>A lib/python/asterisk/self_test/test_buildoptions.py<br>A lib/python/asterisk/self_test/test_cdr.py<br>A lib/python/asterisk/self_test/test_cel.py<br>A lib/python/asterisk/self_test/test_channel_test_condition.py<br>A lib/python/asterisk/self_test/test_config.py<br>A lib/python/asterisk/self_test/test_lock_test_condition.py<br>R lib/python/asterisk/self_test/test_matcher.py<br>A lib/python/asterisk/self_test/test_sip_dialog_test_condition.py.txt<br>A lib/python/asterisk/self_test/test_sippversion.py<br>M lib/python/asterisk/self_test/test_utils_socket.py<br>M lib/python/asterisk/sip_channel_test_condition.py<br>M lib/python/asterisk/sip_dialog_test_condition.py<br>M lib/python/asterisk/sipp.py<br>M lib/python/asterisk/sippversion.py<br>M lib/python/asterisk/syncami.py<br>M lib/python/asterisk/test_case.py<br>M lib/python/asterisk/test_conditions.py<br>M lib/python/asterisk/test_config.py<br>M lib/python/asterisk/test_runner.py<br>M lib/python/asterisk/test_suite_utils.py<br>M lib/python/asterisk/thread_test_condition.py<br>M lib/python/asterisk/voicemail.py<br>M lib/python/rlmi.py<br>M lib/python/sip_message.py<br>M run-local<br>M runtests.py<br>M self_test<br>M tests/cdr/cdr-tests.py<br>M tests/cdr/sqlite3/cdr_sqlite3.py<br>M tests/channels/SIP/tcpauthlimit/sipp_scenario.py<br>M tests/channels/pjsip/registration/inbound/nominal/contact_acl/ipv4/scenario_generator.py<br>M tests/channels/pjsip/registration/inbound/nominal/contact_acl/ipv6/scenario_generator.py<br>M tests/channels/pjsip/subscriptions/presence/verify_bodies/presence.py<br>M tests/channels/pjsip/subscriptions/rls/rls_test.py<br>M tests/channels/pjsip/transfers/attended_transfer/nominal/packet_sniffer.py<br>M tests/codecs/audio_analyzer.py<br>M tests/codecs/rtp_analyzer.py<br>M tests/hep/hep_capture_node.py<br>M tests/manager/config/ManagerConfigTest.py<br>M tests/manager/device_state_changed/ami_device_state.py<br>M tests/manager/device_state_list/ami_device_state_list.py<br>M tests/manager/exten_state_list/ami_exten_state_list.py<br>M tests/manager/presence_state_changed/ami_presence_state.py<br>M tests/manager/presence_state_list/ami_presence_state_list.py<br>M tests/pbx/manager_extensions/ami_extension_control.py<br>M tests/rest_api/external_interaction/attended_transfer/attended_transfer.py<br>M tests/rest_api/external_interaction/blind_transfer/call_transfer.py<br>M tests/rest_api/message/message_modules.py<br>M usage.py<br>85 files changed, 1,910 insertions(+), 1,841 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/testsuite refs/changes/14/9314/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/lib/python/asterisk/ami.py b/lib/python/asterisk/ami.py<br>index fb52d1c..2e0fe4e 100644<br>--- a/lib/python/asterisk/ami.py<br>+++ b/lib/python/asterisk/ami.py<br>@@ -13,7 +13,8 @@<br> import logging<br> import re<br> import json<br>-from pluggable_registry import PLUGGABLE_EVENT_REGISTRY,\<br>+from .test_runner import load_and_parse_module<br>+from .pluggable_registry import PLUGGABLE_EVENT_REGISTRY,\<br> PLUGGABLE_ACTION_REGISTRY, var_replace<br> <br> LOGGER = logging.getLogger(__name__)<br>@@ -361,7 +362,7 @@<br> lower_key = key.lower()<br> if lower_key == 'extra':<br> value = dict((key.lower(), value)<br>- for key, value in value.iteritems())<br>+ for key, value in value.items())<br> self.requirements[lower_key] = value<br> self.orderings = requirements.get('partialorder') or []<br> self.named_id = requirements.get('id')<br>@@ -529,8 +530,7 @@<br> <br> def event_callback(self, ami, event):<br> """Callback called when an event is received from AMI"""<br>- callback_module = __import__(self.callback_module)<br>- method = getattr(callback_module, self.callback_method)<br>+ method = load_and_parse_module(self.callback_module + '.' + self.callback_method)<br> self.passed = method(ami, event)<br> if self.passed is None:<br> LOGGER.error("Callback %s.%s returned None instead of a boolean",<br>@@ -828,7 +828,7 @@<br> <br> def replace_ami_vars(mydict, values):<br> outdict = {}<br>- for key, value in mydict.iteritems():<br>+ for key, value in mydict.items():<br> outdict[key] = var_replace(value, values)<br> <br> return outdict<br>diff --git a/lib/python/asterisk/apptest.py b/lib/python/asterisk/apptest.py<br>index 1fc8496..2c33ad9 100644<br>--- a/lib/python/asterisk/apptest.py<br>+++ b/lib/python/asterisk/apptest.py<br>@@ -18,8 +18,8 @@<br> from twisted.internet import reactor, defer<br> <br> sys.path.append("lib/python")<br>-from test_case import TestCase<br>-from ami import AMIEventInstance<br>+from .test_case import TestCase<br>+from .ami import AMIEventInstance<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>@@ -165,7 +165,7 @@<br> A Scenario is considered done if all results have been met and<br> all expected actions have been executed.<br> """<br>- return (all(self._expected_results.itervalues()) and<br>+ return (all(self._expected_results.values()) and<br> all(i.ran_actions or i.unexpected<br> for i in self._event_instances))<br> <br>diff --git a/lib/python/asterisk/ari.py b/lib/python/asterisk/ari.py<br>index da19cee..23672dd 100644<br>--- a/lib/python/asterisk/ari.py<br>+++ b/lib/python/asterisk/ari.py<br>@@ -12,12 +12,16 @@<br> import re<br> import requests<br> import traceback<br>-import urllib<br>+try:<br>+ from urllib.parse import urlencode<br>+except:<br>+ from urllib import urlencode<br> <br>-from test_case import TestCase<br>-from pluggable_registry import PLUGGABLE_EVENT_REGISTRY,\<br>+from .test_case import TestCase<br>+from .test_runner import load_and_parse_module<br>+from .pluggable_registry import PLUGGABLE_EVENT_REGISTRY,\<br> PLUGGABLE_ACTION_REGISTRY, var_replace<br>-from test_suite_utils import all_match<br>+from .test_suite_utils import all_match<br> from twisted.internet import reactor<br> try:<br> from autobahn.websocket import WebSocketClientFactory, \<br>@@ -332,7 +336,7 @@<br> """<br> url = "ws://%s:%d/ari/events?%s" % \<br> (host, port,<br>- urllib.urlencode({'app': apps, 'api_key': '%s:%s' % userpass}))<br>+ urlencode({'app': apps, 'api_key': '%s:%s' % userpass}))<br> if subscribe_all:<br> url += '&subscribeAll=true'<br> LOGGER.info("WebSocketClientFactory(url=%s)", url)<br>@@ -560,7 +564,7 @@<br> url = self.ari.build_url(uri)<br> requests_method = getattr(requests, self.method)<br> params = dict((key, var_replace(val, values))<br>- for key, val in self.params.iteritems())<br>+ for key, val in self.params.items())<br> <br> response = requests_method(<br> url,<br>@@ -580,7 +584,7 @@<br> response.status_code, response.text)<br> return False<br> else:<br>- if response.status_code / 100 != 2:<br>+ if response.status_code // 100 != 2:<br> LOGGER.error('sent %s %s %s response %d %s',<br> self.method, self.uri, self.params,<br> response.status_code, response.text)<br>@@ -606,8 +610,7 @@<br> <br> callback = self.instance_config.get('callback')<br> if callback:<br>- module = __import__(callback['module'])<br>- self.callback = getattr(module, callback['method'])<br>+ self.callback = load_and_parse_module(callback['module'] + '.' + callback['method'])<br> else:<br> # No callback; just use a no-op<br> self.callback = lambda *args, **kwargs: True<br>diff --git a/lib/python/asterisk/astconfigparser.py b/lib/python/asterisk/astconfigparser.py<br>index dc79e80..e8da255 100644<br>--- a/lib/python/asterisk/astconfigparser.py<br>+++ b/lib/python/asterisk/astconfigparser.py<br>@@ -8,8 +8,7 @@<br> import re<br> import itertools<br> <br>-from astdicts import OrderedDict<br>-from astdicts import MultiOrderedDict<br>+from .astdicts import OrderedDict, MultiOrderedDict<br> <br> <br> def merge_values(left, right, key):<br>@@ -270,11 +269,11 @@<br> <br> def write_dicts(config_file, mdicts):<br> """Write the contents of the mdicts to the specified config file"""<br>- for section, sect_list in mdicts.iteritems():<br>+ for section, sect_list in mdicts.items():<br> # every section contains a list of dictionaries<br> for sect in sect_list:<br> config_file.write("[%s]\n" % section)<br>- for key, val_list in sect.iteritems():<br>+ for key, val_list in sect.items():<br> # every value is also a list<br> for v in val_list:<br> key_val = key<br>@@ -355,7 +354,7 @@<br> if self._includes:<br> res.extend(list(itertools.chain(*[<br> incl.get_sections(key, attr, searched)<br>- for incl in self._includes.itervalues()])))<br>+ for incl in self._includes.values()])))<br> if self._parent:<br> res += self._parent.get_sections(key, attr, searched)<br> return res<br>@@ -445,7 +444,7 @@<br> with open(filename, 'rt') as config_file:<br> self._read(config_file, sect)<br> except IOError:<br>- print "Could not open file ", filename, " for reading"<br>+ print("Could not open file ", filename, " for reading")<br> <br> def _read(self, config_file, sect):<br> """Parse configuration information from the config_file"""<br>@@ -478,7 +477,7 @@<br> def write(self, config_file):<br> """Write configuration information out to a file"""<br> try:<br>- for key, val in self._includes.iteritems():<br>+ for key, val in self._includes.items():<br> val.write(key)<br> config_file.write('#include "%s"\n' % key)<br> <br>@@ -490,4 +489,4 @@<br> with open(config_file, 'wt') as fp:<br> self.write(fp)<br> except IOError:<br>- print "Could not open file ", config_file, " for writing"<br>+ print("Could not open file ", config_file, " for writing")<br>diff --git a/lib/python/asterisk/astcsv.py b/lib/python/asterisk/astcsv.py<br>index 67d25d3..7619bf5 100644<br>--- a/lib/python/asterisk/astcsv.py<br>+++ b/lib/python/asterisk/astcsv.py<br>@@ -1,4 +1,3 @@<br>-#!/usr/bin/env python<br> """Asterisk CSV-based testing<br> <br> This module implements the basic CSV testing backend for things like<br>@@ -11,7 +10,6 @@<br> the GNU General Public License Version 2.<br> """<br> <br>-import unittest<br> import sys<br> import csv<br> import re<br>@@ -57,10 +55,10 @@<br> else:<br> cmp_fn = (lambda x, y: str(x).lower() == str(y).lower())<br> <br>- for key, value in self.iteritems():<br>+ for key, value in self.items():<br> if None not in (value, other.get(key)) and not cmp_fn(value, other.get(key)):<br> if not silent:<br>- LOGGER.warn("CSV MATCH FAILED, Expected: %s: '%s' "<br>+ LOGGER.warning("CSV MATCH FAILED, Expected: %s: '%s' "<br> "Got: %s: '%s'" % (key, value, key,<br> other.get(key)))<br> return False<br>@@ -70,9 +68,9 @@<br> """Retrieve a value from the specified column key"""<br> return self.__columns.get(key)<br> <br>- def iteritems(self):<br>+ def items(self):<br> """Iterate over the values in the columns"""<br>- return self.__columns.iteritems()<br>+ return self.__columns.items()<br> <br> def __str__(self):<br> return ",".join(["\"%s\"" % (self.__dict__[x]) for x in self.__fields])<br>@@ -94,12 +92,14 @@<br> self.__records = []<br> <br> csvreader = None<br>+ csvfile = None<br> <br> try:<br>- csvreader = csv.DictReader(open(self.filename, "r"), fields, ",")<br>- except IOError as (errno, strerror):<br>+ csvfile = open(self.filename, "r")<br>+ csvreader = csv.DictReader(csvfile, fields, ",")<br>+ except IOError as e:<br> LOGGER.error("IOError %d[%s] while opening file '%s'" %<br>- (errno, strerror, self.filename))<br>+ (e.errno, e.strerror, self.filename))<br> except:<br> LOGGER.error("Unexpected error: %s" % (sys.exc_info()[0]))<br> <br>@@ -110,6 +110,8 @@<br> for row in csvreader:<br> record = self.row_factory(**row)<br> self.__records.append(record)<br>+<br>+ csvfile.close()<br> <br> def __len__(self):<br> return len(self.__records)<br>@@ -125,7 +127,7 @@<br> each record"""<br> <br> if not partial and (len(self) != len(other)):<br>- LOGGER.warn("CSV MATCH FAILED, different number of records, "<br>+ LOGGER.warning("CSV MATCH FAILED, different number of records, "<br> "self=%d and other=%d" % (len(self), len(other)))<br> return False<br> <br>@@ -147,7 +149,7 @@<br> size = len(list_a)<br> <br> # attempt two orderings: forward and reversed<br>- guess_orders = (range(size), list(reversed(range(size))))<br>+ guess_orders = (list(range(size)), list(reversed(range(size))))<br> found_orders = []<br> <br> for guess_order in guess_orders:<br>@@ -185,7 +187,7 @@<br> # have it complain immediately.<br> for i, item in enumerate(self):<br> if not item.match(other[i], exact=exactness):<br>- LOGGER.warn("Failed to match entry %d" % (i,))<br>+ LOGGER.warning("Failed to match entry %d" % (i,))<br> return False<br> assert False<br> <br>@@ -193,7 +195,7 @@<br> pass # joy!<br> <br> elif len(matches) > 1:<br>- LOGGER.warn("More than one CSV permutation results in success")<br>+ LOGGER.warning("More than one CSV permutation results in success")<br> <br> return True<br> <br>@@ -205,9 +207,6 @@<br> try:<br> open(self.filename, "w").close()<br> except:<br>- LOGGER.warn("Unable to empty CSV file %s" % (self.filename))<br>-<br>-if __name__ == '__main__':<br>- unittest.main()<br>+ LOGGER.warning("Unable to empty CSV file %s" % (self.filename))<br> <br> # vim:sw=4:ts=4:expandtab:textwidth=79<br>diff --git a/lib/python/asterisk/astdicts.py b/lib/python/asterisk/astdicts.py<br>index ae63075..4e70eec 100644<br>--- a/lib/python/asterisk/astdicts.py<br>+++ b/lib/python/asterisk/astdicts.py<br>@@ -3,260 +3,264 @@<br> # copied from http://code.activestate.com/recipes/576693/<br> <br> try:<br>- from thread import get_ident as _get_ident<br>+ # Use builtin OrderedDict() from Python2.7.<br>+ from collections import OrderedDict<br> except ImportError:<br>- from dummy_thread import get_ident as _get_ident<br>+ try:<br>+ from thread import get_ident as _get_ident<br>+ except ImportError:<br>+ from dummy_thread import get_ident as _get_ident<br> <br>-try:<br>- from _abcoll import KeysView, ValuesView, ItemsView<br>-except ImportError:<br>- pass<br>+ try:<br>+ from _abcoll import KeysView, ValuesView, ItemsView<br>+ except ImportError:<br>+ pass<br> <br> <br>-class OrderedDict(dict):<br>- 'Dictionary that remembers insertion order'<br>- # An inherited dict maps keys to values.<br>- # The inherited dict provides __getitem__, __len__, __contains__, and get.<br>- # The remaining methods are order-aware.<br>- # Big-O running times for all methods are the same as for regular dictionaries.<br>+ class OrderedDict(dict):<br>+ 'Dictionary that remembers insertion order'<br>+ # An inherited dict maps keys to values.<br>+ # The inherited dict provides __getitem__, __len__, __contains__, and get.<br>+ # The remaining methods are order-aware.<br>+ # Big-O running times for all methods are the same as for regular dictionaries.<br> <br>- # The internal self.__map dictionary maps keys to links in a doubly linked list.<br>- # The circular doubly linked list starts and ends with a sentinel element.<br>- # The sentinel element never gets deleted (this simplifies the algorithm).<br>- # Each link is stored as a list of length three: [PREV, NEXT, KEY].<br>+ # The internal self.__map dictionary maps keys to links in a doubly linked list.<br>+ # The circular doubly linked list starts and ends with a sentinel element.<br>+ # The sentinel element never gets deleted (this simplifies the algorithm).<br>+ # Each link is stored as a list of length three: [PREV, NEXT, KEY].<br> <br>- def __init__(self, *args, **kwds):<br>- '''Initialize an ordered dictionary. Signature is the same as for<br>- regular dictionaries, but keyword arguments are not recommended<br>- because their insertion order is arbitrary.<br>+ def __init__(self, *args, **kwds):<br>+ '''Initialize an ordered dictionary. Signature is the same as for<br>+ regular dictionaries, but keyword arguments are not recommended<br>+ because their insertion order is arbitrary.<br> <br>- '''<br>- if len(args) > 1:<br>- raise TypeError('expected at most 1 arguments, got %d' % len(args))<br>- try:<br>- self.__root<br>- except AttributeError:<br>- self.__root = root = [] # sentinel node<br>- root[:] = [root, root, None]<br>- self.__map = {}<br>- self.__update(*args, **kwds)<br>+ '''<br>+ if len(args) > 1:<br>+ raise TypeError('expected at most 1 arguments, got %d' % len(args))<br>+ try:<br>+ self.__root<br>+ except AttributeError:<br>+ self.__root = root = [] # sentinel node<br>+ root[:] = [root, root, None]<br>+ self.__map = {}<br>+ self.__update(*args, **kwds)<br> <br>- def __setitem__(self, key, value, dict_setitem=dict.__setitem__):<br>- 'od.__setitem__(i, y) <==> od[i]=y'<br>- # Setting a new item creates a new link which goes at the end of the linked<br>- # list, and the inherited dictionary is updated with the new key/value pair.<br>- if key not in self:<br>+ def __setitem__(self, key, value, dict_setitem=dict.__setitem__):<br>+ 'od.__setitem__(i, y) <==> od[i]=y'<br>+ # Setting a new item creates a new link which goes at the end of the linked<br>+ # list, and the inherited dictionary is updated with the new key/value pair.<br>+ if key not in self:<br>+ root = self.__root<br>+ last = root[0]<br>+ last[1] = root[0] = self.__map[key] = [last, root, key]<br>+ dict_setitem(self, key, value)<br>+<br>+ def __delitem__(self, key, dict_delitem=dict.__delitem__):<br>+ 'od.__delitem__(y) <==> del od[y]'<br>+ # Deleting an existing item uses self.__map to find the link which is<br>+ # then removed by updating the links in the predecessor and successor nodes.<br>+ dict_delitem(self, key)<br>+ link_prev, link_next, key = self.__map.pop(key)<br>+ link_prev[1] = link_next<br>+ link_next[0] = link_prev<br>+<br>+ def __iter__(self):<br>+ 'od.__iter__() <==> iter(od)'<br> root = self.__root<br>- last = root[0]<br>- last[1] = root[0] = self.__map[key] = [last, root, key]<br>- dict_setitem(self, key, value)<br>+ curr = root[1]<br>+ while curr is not root:<br>+ yield curr[2]<br>+ curr = curr[1]<br> <br>- def __delitem__(self, key, dict_delitem=dict.__delitem__):<br>- 'od.__delitem__(y) <==> del od[y]'<br>- # Deleting an existing item uses self.__map to find the link which is<br>- # then removed by updating the links in the predecessor and successor nodes.<br>- dict_delitem(self, key)<br>- link_prev, link_next, key = self.__map.pop(key)<br>- link_prev[1] = link_next<br>- link_next[0] = link_prev<br>-<br>- def __iter__(self):<br>- 'od.__iter__() <==> iter(od)'<br>- root = self.__root<br>- curr = root[1]<br>- while curr is not root:<br>- yield curr[2]<br>- curr = curr[1]<br>-<br>- def __reversed__(self):<br>- 'od.__reversed__() <==> reversed(od)'<br>- root = self.__root<br>- curr = root[0]<br>- while curr is not root:<br>- yield curr[2]<br>- curr = curr[0]<br>-<br>- def clear(self):<br>- 'od.clear() -> None. Remove all items from od.'<br>- try:<br>- for node in self.__map.itervalues():<br>- del node[:]<br>+ def __reversed__(self):<br>+ 'od.__reversed__() <==> reversed(od)'<br> root = self.__root<br>- root[:] = [root, root, None]<br>- self.__map.clear()<br>- except AttributeError:<br>- pass<br>- dict.clear(self)<br>+ curr = root[0]<br>+ while curr is not root:<br>+ yield curr[2]<br>+ curr = curr[0]<br> <br>- def popitem(self, last=True):<br>- '''od.popitem() -> (k, v), return and remove a (key, value) pair.<br>- Pairs are returned in LIFO order if last is true or FIFO order if false.<br>+ def clear(self):<br>+ 'od.clear() -> None. Remove all items from od.'<br>+ try:<br>+ for node in self.__map.itervalues():<br>+ del node[:]<br>+ root = self.__root<br>+ root[:] = [root, root, None]<br>+ self.__map.clear()<br>+ except AttributeError:<br>+ pass<br>+ dict.clear(self)<br> <br>- '''<br>- if not self:<br>- raise KeyError('dictionary is empty')<br>- root = self.__root<br>- if last:<br>- link = root[0]<br>- link_prev = link[0]<br>- link_prev[1] = root<br>- root[0] = link_prev<br>- else:<br>- link = root[1]<br>- link_next = link[1]<br>- root[1] = link_next<br>- link_next[0] = root<br>- key = link[2]<br>- del self.__map[key]<br>- value = dict.pop(self, key)<br>- return key, value<br>+ def popitem(self, last=True):<br>+ '''od.popitem() -> (k, v), return and remove a (key, value) pair.<br>+ Pairs are returned in LIFO order if last is true or FIFO order if false.<br> <br>- # -- the following methods do not depend on the internal structure --<br>-<br>- def keys(self):<br>- 'od.keys() -> list of keys in od'<br>- return list(self)<br>-<br>- def values(self):<br>- 'od.values() -> list of values in od'<br>- return [self[key] for key in self]<br>-<br>- def items(self):<br>- 'od.items() -> list of (key, value) pairs in od'<br>- return [(key, self[key]) for key in self]<br>-<br>- def iterkeys(self):<br>- 'od.iterkeys() -> an iterator over the keys in od'<br>- return iter(self)<br>-<br>- def itervalues(self):<br>- 'od.itervalues -> an iterator over the values in od'<br>- for k in self:<br>- yield self[k]<br>-<br>- def iteritems(self):<br>- 'od.iteritems -> an iterator over the (key, value) items in od'<br>- for k in self:<br>- yield (k, self[k])<br>-<br>- def update(*args, **kwds):<br>- '''od.update(E, **F) -> None. Update od from dict/iterable E and F.<br>-<br>- If E is a dict instance, does: for k in E: od[k] = E[k]<br>- If E has a .keys() method, does: for k in E.keys(): od[k] = E[k]<br>- Or if E is an iterable of items, does: for k, v in E: od[k] = v<br>- In either case, this is followed by: for k, v in F.items(): od[k] = v<br>-<br>- '''<br>- if len(args) > 2:<br>- raise TypeError('update() takes at most 2 positional '<br>- 'arguments (%d given)' % (len(args),))<br>- elif not args:<br>- raise TypeError('update() takes at least 1 argument (0 given)')<br>- self = args[0]<br>- # Make progressively weaker assumptions about "other"<br>- other = ()<br>- if len(args) == 2:<br>- other = args[1]<br>- if isinstance(other, dict):<br>- for key in other:<br>- self[key] = other[key]<br>- elif hasattr(other, 'keys'):<br>- for key in other.keys():<br>- self[key] = other[key]<br>- else:<br>- for key, value in other:<br>- self[key] = value<br>- for key, value in kwds.items():<br>- self[key] = value<br>-<br>- __update = update # let subclasses override update without breaking __init__<br>-<br>- __marker = object()<br>-<br>- def pop(self, key, default=__marker):<br>- '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.<br>- If key is not found, d is returned if given, otherwise KeyError is raised.<br>-<br>- '''<br>- if key in self:<br>- result = self[key]<br>- del self[key]<br>- return result<br>- if default is self.__marker:<br>- raise KeyError(key)<br>- return default<br>-<br>- def setdefault(self, key, default=None):<br>- 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'<br>- if key in self:<br>- return self[key]<br>- self[key] = default<br>- return default<br>-<br>- def __repr__(self, _repr_running={}):<br>- 'od.__repr__() <==> repr(od)'<br>- call_key = id(self), _get_ident()<br>- if call_key in _repr_running:<br>- return '...'<br>- _repr_running[call_key] = 1<br>- try:<br>+ '''<br> if not self:<br>- return '%s()' % (self.__class__.__name__,)<br>- return '%s(%r)' % (self.__class__.__name__, self.items())<br>- finally:<br>- del _repr_running[call_key]<br>+ raise KeyError('dictionary is empty')<br>+ root = self.__root<br>+ if last:<br>+ link = root[0]<br>+ link_prev = link[0]<br>+ link_prev[1] = root<br>+ root[0] = link_prev<br>+ else:<br>+ link = root[1]<br>+ link_next = link[1]<br>+ root[1] = link_next<br>+ link_next[0] = root<br>+ key = link[2]<br>+ del self.__map[key]<br>+ value = dict.pop(self, key)<br>+ return key, value<br> <br>- def __reduce__(self):<br>- 'Return state information for pickling'<br>- items = [[k, self[k]] for k in self]<br>- inst_dict = vars(self).copy()<br>- for k in vars(OrderedDict()):<br>- inst_dict.pop(k, None)<br>- if inst_dict:<br>- return (self.__class__, (items,), inst_dict)<br>- return self.__class__, (items,)<br>+ # -- the following methods do not depend on the internal structure --<br> <br>- def copy(self):<br>- 'od.copy() -> a shallow copy of od'<br>- return self.__class__(self)<br>+ def keys(self):<br>+ 'od.keys() -> list of keys in od'<br>+ return list(self)<br> <br>- @classmethod<br>- def fromkeys(cls, iterable, value=None):<br>- '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S<br>- and values equal to v (which defaults to None).<br>+ def values(self):<br>+ 'od.values() -> list of values in od'<br>+ return [self[key] for key in self]<br> <br>- '''<br>- d = cls()<br>- for key in iterable:<br>- d[key] = value<br>- return d<br>+ def items(self):<br>+ 'od.items() -> list of (key, value) pairs in od'<br>+ return [(key, self[key]) for key in self]<br> <br>- def __eq__(self, other):<br>- '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive<br>- while comparison to a regular mapping is order-insensitive.<br>+ def iterkeys(self):<br>+ 'od.iterkeys() -> an iterator over the keys in od'<br>+ return iter(self)<br> <br>- '''<br>- if isinstance(other, OrderedDict):<br>- return len(self)==len(other) and self.items() == other.items()<br>- return dict.__eq__(self, other)<br>+ def itervalues(self):<br>+ 'od.itervalues -> an iterator over the values in od'<br>+ for k in self:<br>+ yield self[k]<br> <br>- def __ne__(self, other):<br>- return not self == other<br>+ def iteritems(self):<br>+ 'od.iteritems -> an iterator over the (key, value) items in od'<br>+ for k in self:<br>+ yield (k, self[k])<br> <br>- # -- the following methods are only used in Python 2.7 --<br>+ def update(*args, **kwds):<br>+ '''od.update(E, **F) -> None. Update od from dict/iterable E and F.<br> <br>- def viewkeys(self):<br>- "od.viewkeys() -> a set-like object providing a view on od's keys"<br>- return KeysView(self)<br>+ If E is a dict instance, does: for k in E: od[k] = E[k]<br>+ If E has a .keys() method, does: for k in E.keys(): od[k] = E[k]<br>+ Or if E is an iterable of items, does: for k, v in E: od[k] = v<br>+ In either case, this is followed by: for k, v in F.items(): od[k] = v<br> <br>- def viewvalues(self):<br>- "od.viewvalues() -> an object providing a view on od's values"<br>- return ValuesView(self)<br>+ '''<br>+ if len(args) > 2:<br>+ raise TypeError('update() takes at most 2 positional '<br>+ 'arguments (%d given)' % (len(args),))<br>+ elif not args:<br>+ raise TypeError('update() takes at least 1 argument (0 given)')<br>+ self = args[0]<br>+ # Make progressively weaker assumptions about "other"<br>+ other = ()<br>+ if len(args) == 2:<br>+ other = args[1]<br>+ if isinstance(other, dict):<br>+ for key in other:<br>+ self[key] = other[key]<br>+ elif hasattr(other, 'keys'):<br>+ for key in other.keys():<br>+ self[key] = other[key]<br>+ else:<br>+ for key, value in other:<br>+ self[key] = value<br>+ for key, value in kwds.items():<br>+ self[key] = value<br> <br>- def viewitems(self):<br>- "od.viewitems() -> a set-like object providing a view on od's items"<br>- return ItemsView(self)<br>+ __update = update # let subclasses override update without breaking __init__<br>+<br>+ __marker = object()<br>+<br>+ def pop(self, key, default=__marker):<br>+ '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.<br>+ If key is not found, d is returned if given, otherwise KeyError is raised.<br>+<br>+ '''<br>+ if key in self:<br>+ result = self[key]<br>+ del self[key]<br>+ return result<br>+ if default is self.__marker:<br>+ raise KeyError(key)<br>+ return default<br>+<br>+ def setdefault(self, key, default=None):<br>+ 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'<br>+ if key in self:<br>+ return self[key]<br>+ self[key] = default<br>+ return default<br>+<br>+ def __repr__(self, _repr_running={}):<br>+ 'od.__repr__() <==> repr(od)'<br>+ call_key = id(self), _get_ident()<br>+ if call_key in _repr_running:<br>+ return '...'<br>+ _repr_running[call_key] = 1<br>+ try:<br>+ if not self:<br>+ return '%s()' % (self.__class__.__name__,)<br>+ return '%s(%r)' % (self.__class__.__name__, self.items())<br>+ finally:<br>+ del _repr_running[call_key]<br>+<br>+ def __reduce__(self):<br>+ 'Return state information for pickling'<br>+ items = [[k, self[k]] for k in self]<br>+ inst_dict = vars(self).copy()<br>+ for k in vars(OrderedDict()):<br>+ inst_dict.pop(k, None)<br>+ if inst_dict:<br>+ return (self.__class__, (items,), inst_dict)<br>+ return self.__class__, (items,)<br>+<br>+ def copy(self):<br>+ 'od.copy() -> a shallow copy of od'<br>+ return self.__class__(self)<br>+<br>+ @classmethod<br>+ def fromkeys(cls, iterable, value=None):<br>+ '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S<br>+ and values equal to v (which defaults to None).<br>+<br>+ '''<br>+ d = cls()<br>+ for key in iterable:<br>+ d[key] = value<br>+ return d<br>+<br>+ def __eq__(self, other):<br>+ '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive<br>+ while comparison to a regular mapping is order-insensitive.<br>+<br>+ '''<br>+ if isinstance(other, OrderedDict):<br>+ return len(self)==len(other) and self.items() == other.items()<br>+ return dict.__eq__(self, other)<br>+<br>+ def __ne__(self, other):<br>+ return not self == other<br>+<br>+ # -- the following methods are only used in Python 2.7 --<br>+<br>+ def viewkeys(self):<br>+ "od.viewkeys() -> a set-like object providing a view on od's keys"<br>+ return KeysView(self)<br>+<br>+ def viewvalues(self):<br>+ "od.viewvalues() -> an object providing a view on od's values"<br>+ return ValuesView(self)<br>+<br>+ def viewitems(self):<br>+ "od.viewitems() -> a set-like object providing a view on od's items"<br>+ return ItemsView(self)<br> <br> ###############################################################################<br> ### MultiOrderedDict<br>@@ -292,7 +296,7 @@<br> # TODO - find out why for some reason copies<br> # the [] as an [[]], so do manually<br> c = MultiOrderedDict() #self.__class__(self)<br>- for key, val in self.iteritems():<br>+ for key, val in self.items():<br> for v in val:<br> c[key] = v<br> return c<br>diff --git a/lib/python/asterisk/asterisk.py b/lib/python/asterisk/asterisk.py<br>old mode 100755<br>new mode 100644<br>index 985afea..c3996f6<br>--- a/lib/python/asterisk/asterisk.py<br>+++ b/lib/python/asterisk/asterisk.py<br>@@ -1,4 +1,3 @@<br>-#!/usr/bin/env python<br> """Asterisk Instances in Python.<br> <br> This module provides an interface for creating instances of Asterisk<br>@@ -18,9 +17,9 @@<br> import logging<br> import fileinput<br> <br>-import test_suite_utils<br>+from . import test_suite_utils<br> <br>-from config import ConfigFile<br>+from .config import ConfigFile<br> <br> from twisted.internet import reactor, protocol, defer, utils, error<br> from twisted.python.failure import Failure<br>@@ -54,7 +53,7 @@<br> def dataReceived(self, data):<br> """Called when we receive data back"""<br> LOGGER.debug(data)<br>- self.output += data<br>+ self.output += data.decode('utf-8', 'ignore')<br> <br> def connectionLost(self, reason):<br> """Called when the connect is lost"""<br>@@ -206,7 +205,8 @@<br> def _set_properties(self, result):<br> """Set the properties based on the result of the<br> getProcessOutputAndValue call"""<br>- self.output, self.err, self.exitcode = result<br>+ bintxt, self.err, self.exitcode = result<br>+ self.output = bintxt.decode('utf-8', 'ignore')<br> <br> <br> class AsteriskProtocol(protocol.ProcessProtocol):<br>@@ -232,7 +232,7 @@<br> <br> def outReceived(self, data):<br> """Override of ProcessProtocol.outReceived"""<br>- self.output += data<br>+ self.output += data.decode('utf-8', 'ignore')<br> <br> def connectionMade(self):<br> """Override of ProcessProtocol.connectionMade"""<br>@@ -311,20 +311,6 @@<br> we're not running into the asterisk.ctl AF_UNIX limit.<br> """<br> <br>- def compare_free_space(x, y):<br>- if os.stat(y).st_dev == os.stat(x).st_dev:<br>- return 0<br>- # statvfs can return a long; comparison functions must return an<br>- # int. Where both are same filesystem, bavail might change from<br>- # one call to the next, but hopefully it is not more than 1000.<br>- difference = os.statvfs(y).f_bavail - os.statvfs(x).f_bavail<br>- if (difference > 1000):<br>- return 1<br>- elif (difference < 1000):<br>- return -1<br>- else:<br>- return 0<br>-<br> localtest_root = os.getenv("AST_TEST_ROOT")<br> if localtest_root:<br> # Base location of the temporary files created by the testsuite<br>@@ -333,7 +319,7 @@<br> default_etc_directory = os.path.join(localtest_root, "etc/asterisk")<br> else:<br> # select tmp path with most available space<br>- best_tmp = sorted(['/tmp', '/var/tmp'], cmp=compare_free_space)[0]<br>+ best_tmp = sorted(['/tmp', '/var/tmp'], key=lambda path: os.statvfs(path).f_bavail)[0]<br> # Base location of the temporary files created by the testsuite<br> test_suite_root = best_tmp + "/asterisk-testsuite"<br> # The default etc directory for Asterisk<br>@@ -955,7 +941,7 @@<br> ast_file.write("#include \"%s/asterisk.options.conf.inc\"\n" %<br> (self.astetcdir))<br> if ast_conf_options:<br>- for (var, val) in ast_conf_options.iteritems():<br>+ for (var, val) in ast_conf_options.items():<br> ast_file.write("%s = %s\n" % (var, val))<br> for (var, val) in cat.options:<br> if not ast_conf_options or var not in ast_conf_options:<br>diff --git a/lib/python/asterisk/bridge_test_case.py b/lib/python/asterisk/bridge_test_case.py<br>index ea1767e..155b3a1 100644<br>--- a/lib/python/asterisk/bridge_test_case.py<br>+++ b/lib/python/asterisk/bridge_test_case.py<br>@@ -13,7 +13,7 @@<br> from time import sleep<br> <br> sys.path.append("lib/python")<br>-from test_case import TestCase<br>+from .test_case import TestCase<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>diff --git a/lib/python/asterisk/buildoptions.py b/lib/python/asterisk/buildoptions.py<br>index 3b0b4b9..833053a 100644<br>--- a/lib/python/asterisk/buildoptions.py<br>+++ b/lib/python/asterisk/buildoptions.py<br>@@ -1,4 +1,3 @@<br>-#!/usr/bin/env python<br> """Asterisk Build Options Handling<br> <br> This module implements an Asterisk build options parser. It<br>@@ -13,7 +12,6 @@<br> """<br> <br> import sys<br>-import unittest<br> <br> <br> class AsteriskBuildOptions(object):<br>@@ -51,7 +49,7 @@<br> except IOError:<br> return ret_val<br> except:<br>- print "Unexpected error: %s" % sys.exc_info()[0]<br>+ print("Unexpected error: %s" % sys.exc_info()[0])<br> return ret_val<br> for line in file_lines:<br> if "#define" in line:<br>@@ -59,7 +57,7 @@<br> if (define_tuple[0] == "" or define_tuple[2] == ""):<br> msg = ("Unable to parse build option line [%s] into "<br> "compiler flag token and value" % line)<br>- print msg<br>+ print(msg)<br> else:<br> flag = define_tuple[0].strip()<br> allowed = define_tuple[2].strip()<br>@@ -89,22 +87,3 @@<br> elif expected_value == "0":<br> return True<br> return False<br>-<br>-<br>-class AsteriskBuildOptionsTests(unittest.TestCase):<br>- """Unit tests for AsteriskBuildOptions"""<br>-<br>- def test_1(self):<br>- """Test the defaults paths"""<br>- build_options = AsteriskBuildOptions()<br>- self.assertTrue(1)<br>-<br>-<br>-def main():<br>- """Main entry point for unit tests"""<br>-<br>- unittest.main()<br>-<br>-<br>-if __name__ == "__main__":<br>- main()<br>diff --git a/lib/python/asterisk/cdr.py b/lib/python/asterisk/cdr.py<br>index cc5226b..c5d62db 100644<br>--- a/lib/python/asterisk/cdr.py<br>+++ b/lib/python/asterisk/cdr.py<br>@@ -1,4 +1,3 @@<br>-#!/usr/bin/env python<br> """Asterisk call detail record testing<br> <br> This module implements an Asterisk CDR parser.<br>@@ -10,9 +9,8 @@<br> the GNU General Public License Version 2.<br> """<br> <br>-import unittest<br> import sys<br>-import astcsv<br>+from . import astcsv<br> import logging<br> <br> LOGGER = logging.getLogger(__name__)<br>@@ -137,33 +135,5 @@<br> self, filename, records,<br> AsteriskCSVCDRLine.fields, AsteriskCSVCDRLine)<br> <br>-<br>-class AsteriskCSVCDRTests(unittest.TestCase):<br>- """Unit tests for AsteriskCSVCDR"""<br>-<br>- def test_cdr(self):<br>- """Test the self_test/Master.csv record"""<br>-<br>- cdr = AsteriskCSVCDR("self_test/Master.csv")<br>- self.assertEqual(len(cdr), 2)<br>- self.assertTrue(<br>- AsteriskCSVCDRLine(duration=7, lastapp="hangup").match(<br>- cdr[0],<br>- exact=(True, True)))<br>- self.assertTrue(cdr[0].match(<br>- AsteriskCSVCDRLine(duration=7, lastapp="hangup"),<br>- exact=(True, True)))<br>-<br>- self.assertFalse(cdr[1].match(cdr[0]))<br>- self.assertFalse(cdr[0].match(cdr[1]))<br>- self.assertEqual(cdr[0].billsec, "7")<br>-<br>- self.assertTrue(cdr.match(cdr))<br>- cdr2 = AsteriskCSVCDR("self_test/Master2.csv")<br>- self.assertFalse(cdr.match(cdr2))<br>-<br>-<br>-if __name__ == '__main__':<br>- unittest.main()<br> <br> # vim:sw=4:ts=4:expandtab:textwidth=79<br>diff --git a/lib/python/asterisk/cel.py b/lib/python/asterisk/cel.py<br>index d22d67f..9965270 100644<br>--- a/lib/python/asterisk/cel.py<br>+++ b/lib/python/asterisk/cel.py<br>@@ -1,4 +1,3 @@<br>-#!/usr/bin/env python<br> """Asterisk call detail record testing<br> <br> This module implements an Asterisk CEL parser.<br>@@ -11,8 +10,7 @@<br> """<br> <br> import yaml<br>-import unittest<br>-import astcsv<br>+from . import astcsv<br> import re<br> import logging<br> <br>@@ -176,37 +174,5 @@<br> self, filename, records,<br> AsteriskCSVCELLine.fields, AsteriskCSVCELLine)<br> <br>-<br>-class AsteriskCSVCELTests(unittest.TestCase):<br>- """Unit tests for AsteriskCSVCEL"""<br>-<br>- def test_cel(self):<br>- """Test CEL using self_test/CELMaster1.csv"""<br>-<br>- cel = AsteriskCSVCEL("self_test/CELMaster1.csv")<br>- self.assertEqual(len(cel), 16)<br>- self.assertTrue(AsteriskCSVCELLine(<br>- eventtype="LINKEDID_END",<br>- channel="TinCan/string").match(cel[-1],<br>- silent=True,<br>- exact=(True, True)))<br>- self.assertTrue(cel[-1].match(<br>- AsteriskCSVCELLine(eventtype="LINKEDID_END",<br>- channel="TinCan/string"),<br>- silent=True,<br>- exact=(True, True)))<br>-<br>- self.assertFalse(cel[1].match(cel[0], silent=True))<br>- self.assertFalse(cel[0].match(cel[1], silent=True))<br>- self.assertEqual(cel[-1].channel, "TinCan/string")<br>-<br>- self.assertTrue(cel.match(cel))<br>- cel2 = AsteriskCSVCEL("self_test/CELMaster2.csv")<br>- self.assertFalse(cel.match(cel2))<br>-<br>-<br>-if __name__ == '__main__':<br>- logging.basicConfig()<br>- unittest.main()<br> <br> # vim:sw=4:ts=4:expandtab:textwidth=79<br>diff --git a/lib/python/asterisk/channel_test_condition.py b/lib/python/asterisk/channel_test_condition.py<br>index ec1d774..36421a4 100644<br>--- a/lib/python/asterisk/channel_test_condition.py<br>+++ b/lib/python/asterisk/channel_test_condition.py<br>@@ -1,4 +1,3 @@<br>-#!/usr/bin/env python<br> """Test condition for channels<br> <br> Copyright (C) 2011-2012, Digium, Inc.<br>@@ -9,9 +8,7 @@<br> """<br> <br> from twisted.internet import defer<br>-from test_conditions import TestCondition<br>-import logging<br>-import unittest<br>+from .test_conditions import TestCondition<br> import re<br> <br> <br>@@ -86,155 +83,3 @@<br> defer.DeferredList(exec_list).addCallback(_raise_finished,<br> finish_deferred)<br> return finish_deferred<br>-<br>-<br>-class AstMockOutput(object):<br>- """mock cli output base class"""<br>-<br>- def __init__(self):<br>- """Constructor"""<br>- self.host = "127.0.0.1"<br>-<br>- def MockDefer(self, output):<br>- """use real defer to mock deferred output"""<br>- self.output = output<br>- deferred = defer.Deferred()<br>- deferred.callback(self)<br>- return deferred<br>-<br>-<br>-class AstMockObjectInactive(AstMockOutput):<br>- """mock cli output showing no active channels"""<br>-<br>- def cli_exec(self, command):<br>- """presume command is core show channels and generate output"""<br>- output = ""<br>- output += "Channel Location State Application(Data)\n"<br>- output += "0 active channels\n"<br>- output += "0 active calls\n"<br>- output += "2 calls processed\n"<br>- output += "Asterisk ending (0).\n"<br>- return self.MockDefer(output)<br>-<br>-<br>-class AstMockObjectSingle(AstMockOutput):<br>- """mock cli output showing single active channel"""<br>-<br>- def cli_exec(self, command):<br>- """presume command is core show channels and generate output"""<br>- output = ""<br>- output += "Channel Location State Application(Data)\n"<br>- output += "Local/123@default-00 (None) Down ()\n"<br>- output += "1 active channels\n"<br>- output += "0 active calls\n"<br>- output += "2 calls processed\n"<br>- output += "Asterisk ending (0).\n"<br>- return self.MockDefer(output)<br>-<br>-<br>-class AstMockObjectMultiple(AstMockOutput):<br>- """mock cli output showing multiple active channels"""<br>-<br>- def cli_exec(self, command):<br>- """presume command is core show channels and generate output"""<br>- output = ""<br>- output += "Channel Location State Application(Data)\n"<br>- output += "PJSIP/123@default-00 (None) Down ()\n"<br>- output += "Local/123@default-00 (None) Down ()\n"<br>- output += "SIP/alice@default-00 (None) Down ()\n"<br>- output += "3 active channels\n"<br>- output += "0 active calls\n"<br>- output += "2 calls processed\n"<br>- output += "Asterisk ending (0).\n"<br>- return self.MockDefer(output)<br>-<br>-<br>-class AstMockObjectLeaked(AstMockOutput):<br>- """mock cli output showing leaked channel"""<br>-<br>- def cli_exec(self, command):<br>- """presume command is core show channels and generate output"""<br>- output = ""<br>- output += "Channel Location State Application(Data)\n"<br>- output += "Local/123@default-00 (None) Down ()\n"<br>- output += "0 active channels\n"<br>- output += "0 active calls\n"<br>- output += "2 calls processed\n"<br>- output += "Asterisk ending (0).\n"<br>- return self.MockDefer(output)<br>-<br>-<br>-class TestConfig(object):<br>- """Fake TestConfig object for unittest"""<br>-<br>- def __init__(self):<br>- self.class_type_name = "bogus"<br>- self.config = {}<br>- self.enabled = True<br>- self.pass_expected = True<br>-<br>-<br>-class ChannelTestConditionUnitTest(unittest.TestCase):<br>- """Unit Tests for ChannelTestCondition"""<br>-<br>- def test_evaluate_inactive(self):<br>- """test inactive channel condition"""<br>- obj = ChannelTestCondition(TestConfig())<br>- obj.register_asterisk_instance(AstMockObjectInactive())<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Passed')<br>-<br>- def test_evaluate_multiple_fail(self):<br>- """test multiple channel condition"""<br>- obj = ChannelTestCondition(TestConfig())<br>- obj.register_asterisk_instance(AstMockObjectMultiple())<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Failed')<br>-<br>- def test_evaluate_multiple_fail2(self):<br>- """test multiple channel condition"""<br>- obj = ChannelTestCondition(TestConfig())<br>- obj.allowed_channels = 2<br>- obj.register_asterisk_instance(AstMockObjectMultiple())<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Failed')<br>-<br>- def test_evaluate_multiple_pass(self):<br>- """test multiple channel condition"""<br>- obj = ChannelTestCondition(TestConfig())<br>- obj.allowed_channels = 3<br>- obj.register_asterisk_instance(AstMockObjectMultiple())<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Passed')<br>-<br>- def test_evaluate_single_fail(self):<br>- """test single channel condition"""<br>- obj = ChannelTestCondition(TestConfig())<br>- obj.register_asterisk_instance(AstMockObjectSingle())<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Failed')<br>-<br>- def test_evaluate_single_pass(self):<br>- """test single channel condition"""<br>- obj = ChannelTestCondition(TestConfig())<br>- obj.allowed_channels = 1<br>- obj.register_asterisk_instance(AstMockObjectSingle())<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Passed')<br>-<br>- def test_evaluate_leaked(self):<br>- """test leaked channel condition"""<br>- obj = ChannelTestCondition(TestConfig())<br>- obj.register_asterisk_instance(AstMockObjectLeaked())<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Failed')<br>-<br>-<br>-def main():<br>- """Run the unit tests"""<br>-<br>- logging.basicConfig(level=logging.DEBUG)<br>- unittest.main()<br>-<br>-if __name__ == "__main__":<br>- main()<br>diff --git a/lib/python/asterisk/confbridge.py b/lib/python/asterisk/confbridge.py<br>index acca1e7..0ca364d 100644<br>--- a/lib/python/asterisk/confbridge.py<br>+++ b/lib/python/asterisk/confbridge.py<br>@@ -14,7 +14,7 @@<br> import sys<br> import logging<br> <br>-from test_state import TestState<br>+from .test_state import TestState<br> from twisted.internet import reactor<br> <br> sys.path.append("lib/python")<br>diff --git a/lib/python/asterisk/config.py b/lib/python/asterisk/config.py<br>old mode 100755<br>new mode 100644<br>index e26b156..c5662d2<br>--- a/lib/python/asterisk/config.py<br>+++ b/lib/python/asterisk/config.py<br>@@ -1,4 +1,3 @@<br>-#!/usr/bin/env python<br> """Asterisk Configuration File Handling.<br> <br> This module implements interfaces for dealing with Asterisk configuration<br>@@ -18,7 +17,6 @@<br> <br> import sys<br> import re<br>-import unittest<br> import logging<br> <br> LOGGER = logging.getLogger(__name__)<br>@@ -54,7 +52,7 @@<br> match = self.varval_re.match(line)<br> if match is None:<br> if not is_blank_line(line):<br>- LOGGER.warn("Invalid line: '%s'" % line.strip())<br>+ LOGGER.warning("Invalid line: '%s'" % line.strip())<br> return<br> self.options.append((match.group("name"), match.group("value").strip()))<br> <br>@@ -109,94 +107,6 @@<br> )<br> elif len(self.categories) == 0:<br> if not is_blank_line(line):<br>- LOGGER.warn("Invalid line: '%s'" % line.strip())<br>+ LOGGER.warning("Invalid line: '%s'" % line.strip())<br> else:<br> self.categories[-1].parse_line(line)<br>-<br>-<br>-class ConfigFileTests(unittest.TestCase):<br>- """Unit tests for ConfigFile"""<br>-<br>- def test_conf(self):<br>- """Test parsing a blob of config data"""<br>- test = \<br>- "; stuff\n" \<br>- "this line is invalid on purpose\n" \<br>- "[this is] also invalid]\n" \<br>- ";-- comment --;\n" \<br>- ";-- \n" \<br>- "[this is commented out]\n" \<br>- " --;\n" \<br>- "[foo]\n" \<br>- "a = b\n" \<br>- " b = a \n" \<br>- "this line is invalid on purpose\n" \<br>- ";moo\n" \<br>- "c = d;asdadf;adfads;adsfasdf\n" \<br>- " [bar] ;asdfasdf\n" \<br>- "a-b=c-d\n" \<br>- "xyz=x|y|z\n" \<br>- "1234 => 4242,Example Mailbox,root@localhost,,var=val\n" \<br>- "\n" \<br>- "[template](!)\n" \<br>- "foo=bar\n" \<br>- "exten => _NXX.,n,Wait(1)\n" \<br>- "astetcdir => /etc/asterisk\n"<br>-<br>- conf = ConfigFile(fn=None, config_str=test)<br>-<br>- self.assertEqual(len(conf.categories), 3)<br>-<br>- self.assertEqual(conf.categories[0].name, "foo")<br>- self.assertFalse(conf.categories[0].template)<br>- self.assertEqual(len(conf.categories[0].options), 3)<br>- self.assertEqual(conf.categories[0].options[0][0], "a")<br>- self.assertEqual(conf.categories[0].options[0][1], "b")<br>- self.assertEqual(conf.categories[0].options[1][0], "b")<br>- self.assertEqual(conf.categories[0].options[1][1], "a")<br>- self.assertEqual(conf.categories[0].options[2][0], "c")<br>- self.assertEqual(conf.categories[0].options[2][1], "d")<br>-<br>- self.assertEqual(conf.categories[1].name, "bar")<br>- self.assertFalse(conf.categories[1].template)<br>- self.assertEqual(len(conf.categories[1].options), 3)<br>- self.assertEqual(conf.categories[1].options[0][0], "a-b")<br>- self.assertEqual(conf.categories[1].options[0][1], "c-d")<br>- self.assertEqual(conf.categories[1].options[1][0], "xyz")<br>- self.assertEqual(conf.categories[1].options[1][1], "x|y|z")<br>- self.assertEqual(conf.categories[1].options[2][0], "1234")<br>- self.assertEqual(conf.categories[1].options[2][1],<br>- "4242,Example Mailbox,root@localhost,,var=val")<br>-<br>- self.assertEqual(conf.categories[2].name, "template")<br>- self.assertTrue(conf.categories[2].template)<br>- self.assertEqual(len(conf.categories[2].options), 3)<br>- self.assertEqual(conf.categories[2].options[0][0], "foo")<br>- self.assertEqual(conf.categories[2].options[0][1], "bar")<br>- self.assertEqual(conf.categories[2].options[1][0], "exten")<br>- self.assertEqual(conf.categories[2].options[1][1],<br>- "_NXX.,n,Wait(1)")<br>- self.assertEqual(conf.categories[2].options[2][0], "astetcdir")<br>- self.assertEqual(conf.categories[2].options[2][1], "/etc/asterisk")<br>-<br>-<br>-def main(argv=None):<br>- """Read in and show a config file, or run unit tests"""<br>-<br>- if argv is None:<br>- argv = sys.argv<br>-<br>- if len(argv) == 2:<br>- conf = ConfigFile(argv[1])<br>- for cat in conf.categories:<br>- LOGGER.debug("[%s]" % cat.name)<br>- for (var, val) in cat.options:<br>- LOGGER.debug("%s = %s" % (var, val))<br>- else:<br>- return unittest.main()<br>-<br>- return 0<br>-<br>-<br>-if __name__ == "__main__":<br>- sys.exit(main() or 0)<br>diff --git a/lib/python/asterisk/fd_test_condition.py b/lib/python/asterisk/fd_test_condition.py<br>index 4a8f869..234af28 100644<br>--- a/lib/python/asterisk/fd_test_condition.py<br>+++ b/lib/python/asterisk/fd_test_condition.py<br>@@ -11,7 +11,7 @@<br> import logging<br> <br> from twisted.internet import defer<br>-from test_conditions import TestCondition<br>+from .test_conditions import TestCondition<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>diff --git a/lib/python/asterisk/lock_test_condition.py b/lib/python/asterisk/lock_test_condition.py<br>index 0296693..805e2ff 100644<br>--- a/lib/python/asterisk/lock_test_condition.py<br>+++ b/lib/python/asterisk/lock_test_condition.py<br>@@ -1,4 +1,3 @@<br>-#!/usr/bin/env python<br> """Held locks test condition<br> <br> Copyright (C) 2011-2012, Digium, Inc.<br>@@ -10,10 +9,9 @@<br> <br> import logging<br> import logging.config<br>-import unittest<br> <br> from twisted.internet import defer<br>-from test_conditions import TestCondition<br>+from .test_conditions import TestCondition<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>@@ -199,7 +197,7 @@<br> def evaluate(self, related_test_condition=None):<br> """Evaluate the condition"""<br> <br>- def __lock_info_obtained(finished_deferred):<br>+ def __lock_info_obtained(lst, finished_deferred):<br> """Callback when lock information has been obtained"""<br> if (len(self.locks) > 0):<br> #Sometimes, a lock will be held at the end of a test run<br>@@ -229,314 +227,3 @@<br> finished_deferred)<br> return finished_deferred<br> <br>-<br>-class AstMockObjectPassed(object):<br>- """A lock output that passed"""<br>-<br>- def __init__(self):<br>- """Constructor"""<br>- self.host = "127.0.0.2"<br>-<br>- def cli_exec(self, command, sync):<br>- """Fake out a CLI command execution"""<br>- lock_lines = "=======================================================================\n"<br>- lock_lines += "=== Currently Held Locks ==============================================\n"<br>- lock_lines += "=======================================================================\n"<br>- lock_lines += "===\n"<br>- lock_lines += "=== <pending> <lock#> (<file>): <lock type> <line num> <function> <lock name> <lock addr> (times locked)\n"<br>- lock_lines += "===\n"<br>- lock_lines += "===\n"<br>- lock_lines += "=======================================================================\n"<br>- return lock_lines<br>-<br>-<br>-class AstMockObjectFailure(object):<br>- """A lock object that failed"""<br>-<br>- def __init__(self):<br>- """Constructor"""<br>- self.host = "127.0.0.1"<br>-<br>- def cli_exec(self, command, sync):<br>- """Fake out a CLI command execution"""<br>- lock_lines = "=======================================================================\n"<br>- lock_lines += "=== Currently Held Locks ==============================================\n"<br>- lock_lines += "=======================================================================\n"<br>- lock_lines += "===\n"<br>- lock_lines += "=== <pending> <lock#> (<file>): <lock type> <line num> <function> <lock name> <lock addr> (times locked)\n"<br>- lock_lines += "===\n"<br>- lock_lines += "=== Thread ID: 0x402c6940 (do_monitor started at [25114] chan_sip.c restart_monitor())\n"<br>- lock_lines += "=== ---> Lock #0 (chan_sip.c): MUTEX 24629 handle_request_do &netlock 0x2aaabe671a40 (1)\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_bt_get_addresses+0x1a) [0x4e9679]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ast_pthread_mutex_lock+0xf6) [0x4e22d9]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/lib/asterisk/modules/chan_sip.so [0x2aaabe423ee8]\n"<br>- lock_lines += "=== ---> Lock #1 (chan_sip.c): MUTEX 24629 handle_request_do &netlock 0x2aaabe671a40 (1)\n"<br>- lock_lines += "=== --- ---> Locked Here: channel.c line 4304 (ast_indicate_data)\n"<br>- lock_lines += "=== -------------------------------------------------------------------\n"<br>- lock_lines += "===\n"<br>- lock_lines += "=== Thread ID: 0x449ec940 (netconsole started at [ 1351] asterisk.c listener())\n"<br>- lock_lines += "=== ---> Waiting for Lock #0 (astobj2.c): MUTEX 842 internal_ao2_iterator_next a->c 0x2aaaac491f50 (1)\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_bt_get_addresses+0x1a) [0x4e9679]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ast_pthread_mutex_lock+0xf6) [0x4e22d9]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_lock+0x53) [0x4456fc]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x446cec]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_iterator_next+0x29) [0x447134]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_channel_iterator_next+0x19) [0x46cf7d]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x489e43]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_cli_command_full+0x222) [0x48eec4]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_cli_command_multiple_full+0x92) [0x48f035]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x43d129]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x5661c6]\n"<br>- lock_lines += "/lib64/libpthread.so.0 [0x3d1d80673d]\n"<br>- lock_lines += "/lib64/libc.so.6(clone+0x6d) [0x3d1ccd44bd]\n"<br>- lock_lines += "=== --- ---> Locked Here: astobj2.c line 657 (internal_ao2_callback)\n"<br>- lock_lines += "=== -------------------------------------------------------------------\n"<br>- lock_lines += "===\n"<br>- lock_lines += "=== Thread ID: 0x44a68940 (netconsole started at [ 1351] asterisk.c listener())\n"<br>- lock_lines += "=== ---> Waiting for Lock #0 (astobj2.c): MUTEX 842 internal_ao2_iterator_next a->c 0x2aaaac491f50 (1)\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_bt_get_addresses+0x1a) [0x4e9679]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ast_pthread_mutex_lock+0xf6) [0x4e22d9]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_lock+0x53) [0x4456fc]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x446cec]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_iterator_next+0x29) [0x447134]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_channel_iterator_next+0x19) [0x46cf7d]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x489e43]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_cli_command_full+0x222) [0x48eec4]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_cli_command_multiple_full+0x92) [0x48f035]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x43d129]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x5661c6]\n"<br>- lock_lines += "/lib64/libpthread.so.0 [0x3d1d80673d]\n"<br>- lock_lines += "/lib64/libc.so.6(clone+0x6d) [0x3d1ccd44bd]\n"<br>- lock_lines += "=== --- ---> Locked Here: astobj2.c line 657 (internal_ao2_callback)\n"<br>- lock_lines += "=== -------------------------------------------------------------------\n"<br>- lock_lines += "===\n"<br>- lock_lines += "=======================================================================\n"<br>- return lock_lines<br>-<br>-<br>-class TestConfig(object):<br>- """Fake TestConfig object"""<br>-<br>- def __init__(self):<br>- """ Values here don't matter much - we just need to have something """<br>- self.class_type_name = "asterisk.LockTestCondition.LockTestCondition"<br>- self.pass_expected = True<br>- self.type = "Post"<br>- self.related_condition = ""<br>- self.config = {}<br>-<br>-<br>-class LockTestConditionUnitTest(unittest.TestCase):<br>- """Unit tests for LockTestCondition"""<br>-<br>- def test_evaluate_failed(self):<br>- """Test a failed locking condition"""<br>- ast = AstMockObjectFailure()<br>- obj = LockTestCondition(TestConfig())<br>- obj.register_asterisk_instance(ast)<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Failed')<br>-<br>- def test_evaluate_pass(self):<br>- """Test a passed locking condition"""<br>- ast = AstMockObjectPassed()<br>- obj = LockTestCondition(TestConfig())<br>- obj.register_asterisk_instance(ast)<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Passed')<br>-<br>- def test_evaluate_multiple(self):<br>- """Test multiple results"""<br>- ast1 = AstMockObjectPassed()<br>- ast2 = AstMockObjectFailure()<br>- obj = LockTestCondition(TestConfig())<br>- obj.register_asterisk_instance(ast1)<br>- obj.register_asterisk_instance(ast2)<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Failed')<br>-<br>-<br>-class LockSequenceUnitTest(unittest.TestCase):<br>- """Tests for parsing a lock sequence"""<br>-<br>- def test_single_object_no_held_info(self):<br>- """Test a lock sequence with no waiting lock"""<br>-<br>- lock_lines = "=== Thread ID: 0x7f668c142700 (do_monitor started at [25915] chan_sip.c restart_monitor())\n"<br>- lock_lines += "=== ---> Lock #0 (chan_sip.c): MUTEX 25390 handle_request_do &netlock 0x7f6652193900 (1)\n"<br>- lock_lines += "main/logger.c:1302 ast_bt_get_addresses() (0x505e53+1D)\n"<br>- lock_lines += "main/lock.c:193 __ast_pthread_mutex_lock() (0x4fe55c+D9)\n"<br>- lock_lines += "channels/chan_sip.c:25393 handle_request_do()\n"<br>- lock_lines += "channels/chan_sip.c:25352 sipsock_read()\n"<br>- lock_lines += "main/io.c:288 ast_io_wait() (0x4f8228+19C)\n"<br>- lock_lines += "channels/chan_sip.c:25882 do_monitor()\n"<br>- lock_lines += "main/utils.c:1010 dummy_start()\n"<br>- lock_lines += "libpthread.so.0 <unknown>()\n"<br>- lock_lines += "libc.so.6 clone() (0x31be0e0bc0+6D)\n"<br>-<br>- obj = LockSequence()<br>- obj.parse_lock_sequence(lock_lines)<br>-<br>- def test_large_multiple_object(self):<br>- """Test with a waiting lock"""<br>-<br>- lock_lines = "=== Thread ID: 0x449ec940 (netconsole started at [ 1351] asterisk.c listener())\n"<br>- lock_lines += "=== ---> Waiting for Lock #0 (astobj2.c): MUTEX 842 internal_ao2_iterator_next a->c 0x2aaaac491f50 (1)\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_bt_get_addresses+0x1a) [0x4e9679]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ast_pthread_mutex_lock+0xf6) [0x4e22d9]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_lock+0x53) [0x4456fc]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x446cec]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_iterator_next+0x29) [0x447134]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_channel_iterator_next+0x19) [0x46cf7d]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x489e43]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_cli_command_full+0x222) [0x48eec4]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_cli_command_multiple_full+0x92) [0x48f035]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x43d129]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x5661c6]\n"<br>- lock_lines += "/lib64/libpthread.so.0 [0x3d1d80673d]\n"<br>- lock_lines += "/lib64/libc.so.6(clone+0x6d) [0x3d1ccd44bd]\n"<br>- lock_lines += "=== --- ---> Locked Here: astobj2.c line 657 (internal_ao2_callback)\n"<br>-<br>- obj = LockSequence()<br>- obj.parse_lock_sequence(lock_lines)<br>- self.assertEqual(obj.thread_id, "0x449ec940")<br>- self.assertEqual(obj.thread_name, "netconsole")<br>- self.assertEqual(obj.thread_line, 1351)<br>- self.assertEqual(obj.thread_file, "asterisk.c")<br>- self.assertEqual(obj.thread_func, "listener")<br>- self.assertTrue(len(obj.locks) == 1)<br>- self.assertEqual(obj.locks[0].locked_file, "astobj2.c")<br>- self.assertEqual(obj.locks[0].locked_line, 657)<br>- self.assertEqual(obj.locks[0].locked_func, "internal_ao2_callback")<br>-<br>- def test_single_object(self):<br>- """Test a lock held somewhere else"""<br>-<br>- lock_lines = "=== Thread ID: 0x402c6940 (do_monitor started at [25114] chan_sip.c restart_monitor())\n"<br>- lock_lines += "=== ---> Lock #0 (chan_sip.c): MUTEX 24629 handle_request_do &netlock 0x2aaabe671a40 (1)\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_bt_get_addresses+0x1a) [0x4e9679]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ast_pthread_mutex_lock+0xf6) [0x4e22d9]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/lib/asterisk/modules/chan_sip.so [0x2aaabe423ee8]\n"<br>- lock_lines += "=== --- ---> Locked Here: channel.c line 4304 (ast_indicate_data)\n"<br>-<br>- obj = LockSequence()<br>- obj.parse_lock_sequence(lock_lines)<br>- self.assertEqual(obj.thread_id, "0x402c6940")<br>- self.assertEqual(obj.thread_name, "do_monitor")<br>- self.assertEqual(obj.thread_line, 25114)<br>- self.assertEqual(obj.thread_file, "chan_sip.c")<br>- self.assertEqual(obj.thread_func, "restart_monitor")<br>- self.assertTrue(len(obj.locks) == 1)<br>- self.assertEqual(obj.locks[0].locked_file, "channel.c")<br>- self.assertEqual(obj.locks[0].locked_line, 4304)<br>- self.assertEqual(obj.locks[0].locked_func, "ast_indicate_data")<br>- self.assertEqual(obj.locks[0].id, 0)<br>- self.assertEqual(obj.locks[0].type, "MUTEX")<br>- self.assertEqual(obj.locks[0].file, "chan_sip.c")<br>- self.assertEqual(obj.locks[0].line_number, 24629)<br>- self.assertEqual(obj.locks[0].func, "handle_request_do")<br>- self.assertEqual(obj.locks[0].name, "&netlock")<br>- self.assertEqual(obj.locks[0].addr, "0x2aaabe671a40")<br>- self.assertEqual(obj.locks[0].lock_count, 1)<br>- self.assertTrue(obj.locks[0].held)<br>- self.assertTrue(len(obj.locks[0].backtrace) == 3)<br>-<br>- def test_multiple_objects_no_backtrace(self):<br>- """Test multiple locks with no backtrace"""<br>-<br>- lock_lines = "=== Thread ID: 0x402c6940 (do_monitor started at [25114] chan_sip.c restart_monitor())\n"<br>- lock_lines += "=== ---> Lock #0 (chan_sip.c): MUTEX 24629 handle_request_do &netlock 0x2aaabe671a40 (1)\n"<br>- lock_lines += "=== ---> Lock #1 (astobj2.c): MUTEX 657 internal_ao2_callback c 0x2aaaac491f50 (1)\n"<br>- lock_lines += "=== ---> Waiting for Lock #2 (channel.c): MUTEX 1691 ast_channel_cmp_cb chan 0x2aaaacd3a4e0 (1)\n"<br>- lock_lines += "=== --- ---> Locked Here: channel.c line 4304 (ast_indicate_data)\n"<br>-<br>- obj = LockSequence()<br>- obj.parse_lock_sequence(lock_lines)<br>- self.assertEqual(obj.thread_id, "0x402c6940")<br>- self.assertEqual(obj.thread_name, "do_monitor")<br>- self.assertEqual(obj.thread_line, 25114)<br>- self.assertEqual(obj.thread_file, "chan_sip.c")<br>- self.assertEqual(obj.thread_func, "restart_monitor")<br>- self.assertTrue(len(obj.locks) == 3)<br>- self.assertEqual(obj.locks[2].locked_file, "channel.c")<br>- self.assertEqual(obj.locks[2].locked_line, 4304)<br>- self.assertEqual(obj.locks[2].locked_func, "ast_indicate_data")<br>- self.assertEqual(obj.locks[0].id, 0)<br>- self.assertEqual(obj.locks[0].type, "MUTEX")<br>- self.assertEqual(obj.locks[0].file, "chan_sip.c")<br>- self.assertEqual(obj.locks[0].line_number, 24629)<br>- self.assertEqual(obj.locks[0].func, "handle_request_do")<br>- self.assertEqual(obj.locks[0].name, "&netlock")<br>- self.assertEqual(obj.locks[0].addr, "0x2aaabe671a40")<br>- self.assertEqual(obj.locks[0].lock_count, 1)<br>- self.assertTrue(obj.locks[0].held)<br>- self.assertTrue(len(obj.locks[0].backtrace) == 0)<br>-<br>-<br>-class LockObjectUnitTest(unittest.TestCase):<br>- """Unit tests for LockObject"""<br>-<br>- def test_no_backtrace(self):<br>- """Test creating a lock object with no thread backtrace"""<br>-<br>- lock_line = "=== ---> Waiting for Lock #0 (sig_ss7.c): MUTEX 636 ss7_linkset &linkset->lock 0x2aaab8a6b588 (1)"<br>- obj = LockObject()<br>- obj.parse_lock_information(lock_line)<br>- self.assertEqual(obj.id, 0)<br>- self.assertEqual(obj.type, "MUTEX")<br>- self.assertEqual(obj.file, "sig_ss7.c")<br>- self.assertEqual(obj.line_number, 636)<br>- self.assertEqual(obj.func, "ss7_linkset")<br>- self.assertEqual(obj.name, "&linkset->lock")<br>- self.assertEqual(obj.addr, "0x2aaab8a6b588")<br>- self.assertEqual(obj.lock_count, 1)<br>- self.assertFalse(obj.held)<br>- self.assertTrue(len(obj.backtrace) == 0)<br>-<br>- def test_with_backtrace(self):<br>- """Test creating a lock object with a thread backtrace"""<br>-<br>- lock_lines = "=== ---> Lock #1 (astobj2.c): MUTEX 657 internal_ao2_callback c 0x2aaaac491f50 (1)\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_bt_get_addresses+0x1a) [0x4e9679]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ast_pthread_mutex_lock+0xf6) [0x4e22d9]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_lock+0x53) [0x4456fc]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x4464be]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_callback+0x59) [0x446a4e]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_find+0x2b) [0x446ba7]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x46d3a7]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_channel_get_by_name+0x24) [0x46d3e3]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/lib/asterisk/modules/func_channel.so [0x2aaabfba2468]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_func_write+0x16a) [0x50aacd]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(pbx_builtin_setvar_helper+0x10e) [0x51fff4]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/lib/asterisk/modules/chan_sip.so [0x2aaabe422d09]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/lib/asterisk/modules/chan_sip.so [0x2aaabe4240a0]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/lib/asterisk/modules/chan_sip.so [0x2aaabe423cf1]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_io_wait+0x1ba) [0x4dc2e4]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/lib/asterisk/modules/chan_sip.so [0x2aaabe425722]\n"<br>- lock_lines += "/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x5661c6]\n"<br>- lock_lines += "/lib64/libpthread.so.0 [0x3d1d80673d]\n"<br>- lock_lines += "/lib64/libc.so.6(clone+0x6d) [0x3d1ccd44bd]\n"<br>-<br>- obj = LockObject()<br>- obj.parse_lock_information(lock_lines)<br>- self.assertEqual(obj.id, 1)<br>- self.assertEqual(obj.type, "MUTEX")<br>- self.assertEqual(obj.file, "astobj2.c")<br>- self.assertEqual(obj.line_number, 657)<br>- self.assertEqual(obj.func, "internal_ao2_callback")<br>- self.assertEqual(obj.name, "c")<br>- self.assertEqual(obj.addr, "0x2aaaac491f50")<br>- self.assertEqual(obj.lock_count, 1)<br>- self.assertTrue(obj.held)<br>- self.assertTrue(len(obj.backtrace) == 19)<br>-<br>-<br>-def main():<br>- """Run the unit tests"""<br>-<br>- logging.basicConfig(level=logging.DEBUG)<br>- unittest.main()<br>-<br>-<br>-if __name__ == "__main__":<br>- main()<br>diff --git a/lib/python/asterisk/matcher.py b/lib/python/asterisk/matcher.py<br>index 3ab9c24..8ef575e 100644<br>--- a/lib/python/asterisk/matcher.py<br>+++ b/lib/python/asterisk/matcher.py<br>@@ -9,13 +9,17 @@<br> """<br> <br> import logging<br>+import sys<br> <br>-from test_suite_utils import all_match<br>-from pluggable_registry import PLUGGABLE_EVENT_REGISTRY,\<br>- PLUGGABLE_ACTION_REGISTRY<br>+from .test_runner import load_and_parse_module<br>+from .test_suite_utils import all_match<br>+from .pluggable_registry import PLUGGABLE_EVENT_REGISTRY<br> <br> <br> LOGGER = logging.getLogger(__name__)<br>+<br>+if sys.version_info[0] == 3:<br>+ unicode = str<br> <br> <br> class ConditionError(Exception):<br>@@ -217,7 +221,6 @@<br> <br> matched.append(c)<br> <br>-<br> if not matched:<br> return False<br> <br>@@ -315,13 +318,9 @@<br> <br> self.triggered_callback = triggered_callback<br> <br>- module_name, _, obj_type = config['type'].partition('.')<br>-<br>- module = __import__(module_name, fromlist=[obj_type])<br>- if not module:<br>- raise Exception("Unable to import module '{0}'.".format(module_name))<br>-<br>- obj = getattr(module, obj_type)<br>+ obj = load_and_parse_module(config['type'])<br>+ if not obj:<br>+ raise Exception("Unable to import module '{0}'.".format(config['type']))<br> <br> self.conditions = obj(config, test_object, self.__handle_match)<br> <br>diff --git a/lib/python/asterisk/matcher_listener.py b/lib/python/asterisk/matcher_listener.py<br>index d6b621d..cd2ca5a 100644<br>--- a/lib/python/asterisk/matcher_listener.py<br>+++ b/lib/python/asterisk/matcher_listener.py<br>@@ -13,7 +13,7 @@<br> from twisted.internet.protocol import DatagramProtocol<br> from twisted.internet import reactor<br> <br>-from matcher import PluggableConditions<br>+from .matcher import PluggableConditions<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>diff --git a/lib/python/asterisk/opensslversion.py b/lib/python/asterisk/opensslversion.py<br>index a7377ea..3fa5cd5 100644<br>--- a/lib/python/asterisk/opensslversion.py<br>+++ b/lib/python/asterisk/opensslversion.py<br>@@ -9,11 +9,10 @@<br> """<br> <br> import sys<br>-import unittest<br> import re<br> sys.path.append("lib/python")<br> <br>-import test_suite_utils<br>+from . import test_suite_utils<br> <br> class OpenSSLVersion:<br> """An OpenSSL Version.<br>diff --git a/lib/python/asterisk/originate.py b/lib/python/asterisk/originate.py<br>index e6befb5..6c87a57 100644<br>--- a/lib/python/asterisk/originate.py<br>+++ b/lib/python/asterisk/originate.py<br>@@ -16,7 +16,7 @@<br> import json<br> import requests<br> <br>-import ari<br>+from . import ari<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>diff --git a/lib/python/asterisk/pcap.py b/lib/python/asterisk/pcap.py<br>index d39574a..cb5fa5c 100644<br>--- a/lib/python/asterisk/pcap.py<br>+++ b/lib/python/asterisk/pcap.py<br>@@ -739,13 +739,14 @@<br> self.callbacks = {}<br> self.traces = {}<br> <br>- def process_packet(self, packet, (host, port)):<br>+ def process_packet(self, packet, addr):<br> """Store a known packet in our traces and call our callbacks<br> <br> Keyword Arguments:<br> packet A raw packet received from ... something.<br>- (host, port) Tuple of received host and port<br>+ addr Tuple of received host and port<br> """<br>+ (host, port) = addr<br> packet = self.packet_factory.interpret_packet(packet)<br> if packet is None:<br> return<br>@@ -812,13 +813,14 @@<br> self.rules = rules<br> self.cb = cb<br> <br>- def datagramReceived(self, data, (host, port)):<br>+ def datagramReceived(self, data, addr):<br> """Callback for when a datagram is received<br> <br> Keyword Arguments:<br> data The actual packet<br>- (host, port) Tuple of source host and port<br>+ addr Tuple of received host and port<br> """<br>+ (host, port) = addr<br> LOGGER.debug('Proxy received from {0}:{1}\n{2}'.format(<br> host, port, data))<br> <br>diff --git a/lib/python/asterisk/phones.py b/lib/python/asterisk/phones.py<br>old mode 100755<br>new mode 100644<br>index 6a96b38..4987da5<br>--- a/lib/python/asterisk/phones.py<br>+++ b/lib/python/asterisk/phones.py<br>@@ -1,4 +1,3 @@<br>-#!/usr/bin/env python<br> """Pluggable modules and classes to simulate phones.<br> <br> Copyright (C) 2015, Digium, Inc.<br>@@ -85,7 +84,7 @@<br> <br> def __setup_pjsua_acc_cb(self):<br> """Setup PJSUA account callbacks"""<br>- for name, phone_obj in self.__pjsua_phones.iteritems():<br>+ for name, phone_obj in self.__pjsua_phones.items():<br> acc_cb = AccCallback()<br> phone_obj.account.set_callback(acc_cb)<br> LOGGER.info("%s is ready to receive calls." % name)<br>@@ -106,7 +105,7 @@<br> if name:<br> return self.__pjsua_phones.get(name)<br> if account:<br>- for name, phone_obj in self.__pjsua_phones.iteritems():<br>+ for name, phone_obj in self.__pjsua_phones.items():<br> if account is phone_obj.account:<br> return phone_obj<br> <br>diff --git a/lib/python/asterisk/pjsua_mod.py b/lib/python/asterisk/pjsua_mod.py<br>index 63add6a..cdf3d18 100644<br>--- a/lib/python/asterisk/pjsua_mod.py<br>+++ b/lib/python/asterisk/pjsua_mod.py<br>@@ -17,6 +17,7 @@<br> sys.path.append("lib/python")<br> <br> from twisted.internet import reactor<br>+from .test_runner import load_and_parse_module<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>@@ -147,7 +148,7 @@<br> self.lib.set_null_snd_dev()<br> self.__create_accounts()<br> self.lib.start()<br>- except pj.Error, exception:<br>+ except pj.Error as exception:<br> LOGGER.error("Exception: " + str(exception))<br> self.lib.destroy()<br> self.lib = None<br>@@ -306,6 +307,5 @@<br> <br> def do_callback(self):<br> """Call the configured callback module/method"""<br>- callback_module = __import__(self.callback_module)<br>- callback_method = getattr(callback_module, self.callback_method)<br>+ callback_method = load_and_parse_module(self.callback_module + '.' + self.callback_method)<br> callback_method(self.test_object, self.pj_accounts)<br>diff --git a/lib/python/asterisk/pluggable_modules.py b/lib/python/asterisk/pluggable_modules.py<br>old mode 100755<br>new mode 100644<br>index 344f908..dddb036<br>--- a/lib/python/asterisk/pluggable_modules.py<br>+++ b/lib/python/asterisk/pluggable_modules.py<br>@@ -1,4 +1,3 @@<br>-#!/usr/bin/env python<br> """Generic pluggable modules<br> <br> Copyright (C) 2012, Digium, Inc.<br>@@ -14,15 +13,15 @@<br> import re<br> <br> sys.path.append("lib/python")<br>-from ami import AMIEventInstance<br>+from .ami import AMIEventInstance<br> from twisted.internet import reactor<br> from starpy import fastagi<br>-from test_runner import load_and_parse_module<br>-from pluggable_registry import PLUGGABLE_ACTION_REGISTRY,\<br>+from .test_runner import load_and_parse_module<br>+from .pluggable_registry import PLUGGABLE_ACTION_REGISTRY,\<br> PLUGGABLE_EVENT_REGISTRY,\<br> PluggableRegistry<br> <br>-import matcher<br>+from . import matcher<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>@@ -576,7 +575,7 @@<br> return<br> <br> current_trigger = config['trigger']['match']<br>- for key, value in current_trigger.iteritems():<br>+ for key, value in current_trigger.items():<br> if key.lower() not in event:<br> LOGGER.debug("Condition %s not in event, returning", key)<br> return<br>@@ -701,8 +700,7 @@<br> if self.commands:<br> return self.execute_command(agi, 0)<br> else:<br>- callback_module = __import__(self.callback_module)<br>- method = getattr(callback_module, self.callback_method)<br>+ method = load_and_parse_module(self.callback_module + '.' + self.callback_method)<br> method(self.test_object, agi)<br> <br> def on_command_failure(self, reason, agi, idx):<br>@@ -784,7 +782,7 @@<br> <br> def register_modules(config, registry):<br> """Register pluggable modules into the registry"""<br>- for key, local_class_path in config.iteritems():<br>+ for key, local_class_path in config.items():<br> local_class = load_and_parse_module(local_class_path)<br> if not local_class:<br> raise Exception("Unable to load %s for module key %s"<br>@@ -804,7 +802,7 @@<br> for e_a_set in config["mapping"]:<br> plug_set = {"events": [], "actions": []}<br> <br>- for plug_name, plug_config in e_a_set.iteritems():<br>+ for plug_name, plug_config in e_a_set.items():<br> self.parse_module_config(plug_set, plug_name, plug_config)<br> <br> if 0 == len(plug_set["events"]):<br>@@ -923,8 +921,7 @@<br> <br> def run(self, triggered_by, source, extra):<br> """Call the callback."""<br>- module = __import__(self.module)<br>- method = getattr(module, self.method)<br>+ method = load_and_parse_module(self.module + '.' + self.method)<br> self.test_object.set_passed(method(self.test_object, triggered_by,<br> source, extra))<br> PLUGGABLE_ACTION_REGISTRY.register("callback", CallbackActionModule)<br>@@ -960,12 +957,12 @@<br> def __init__(self, test_object, config):<br> """Setup the test start observer"""<br> self.test_object = test_object<br>- self.module = __import__("phones")<br>+ self.module = "phones"<br> self.method = config["action"]<br> self.config = config<br> <br> def run(self, triggered_by, source, extra):<br> """Instruct phone to perform action"""<br>- method = getattr(self.module, self.method)<br>+ method = load_and_parse_module(self.module + "." + self.method)<br> method(self.test_object, triggered_by, source, extra, self.config)<br> PLUGGABLE_ACTION_REGISTRY.register("pjsua_phone", PjsuaPhoneActionModule)<br>diff --git a/lib/python/asterisk/pluggable_registry.py b/lib/python/asterisk/pluggable_registry.py<br>old mode 100755<br>new mode 100644<br>index 8169795..9a50a26<br>--- a/lib/python/asterisk/pluggable_registry.py<br>+++ b/lib/python/asterisk/pluggable_registry.py<br>@@ -1,4 +1,3 @@<br>-#!/usr/bin/env python<br> """Pluggable module registries<br> <br> Copyright (C) 2014, Digium, Inc.<br>diff --git a/lib/python/asterisk/realtime_converter.py b/lib/python/asterisk/realtime_converter.py<br>index 3f50b5f..95ae579 100644<br>--- a/lib/python/asterisk/realtime_converter.py<br>+++ b/lib/python/asterisk/realtime_converter.py<br>@@ -9,7 +9,7 @@<br> import os<br> from sqlalchemy import create_engine, MetaData, Table<br> <br>-import astconfigparser<br>+from . import astconfigparser<br> import logging<br> <br> LOGGER = logging.getLogger(__name__)<br>@@ -83,8 +83,8 @@<br> self.filename = filename<br> self.sections = sections<br> # All affected database tables in list form. Used for convenience<br>- self.tables = [table for section in sections.itervalues() for table in<br>- section.itervalues()]<br>+ self.tables = [table for section in sections.values() for table in<br>+ section.values()]<br> self.sorcery = None<br> self.extconfig = None<br> <br>@@ -111,9 +111,9 @@<br> config_dir: The directory where Asterisk configuration can be found<br> """<br> with open(self.sorcery.file, 'a') as sorcery:<br>- for section, items in self.sections.iteritems():<br>+ for section, items in self.sections.items():<br> sorcery.write('[{0}]\n'.format(section))<br>- for obj, table in items.iteritems():<br>+ for obj, table in items.items():<br> sorcery.write('{0} = realtime,{1}\n'.format(obj, table))<br> <br> def write_extconfig_conf(self):<br>@@ -141,7 +141,7 @@<br> """<br> conf = astconfigparser.MultiOrderedConfigParser()<br> conf.read(os.path.join(config_dir, self.filename))<br>- for title, sections in conf.sections().iteritems():<br>+ for title, sections in conf.sections().items():<br> LOGGER.info("Inspecting objects with title {0}".format(title))<br> for section in sections:<br> obj_type = section.get('type')[0]<br>@@ -165,7 +165,7 @@<br> Keyword Arguments:<br> obj_type: The object type to find the section for<br> """<br>- for section, contents in self.sections.iteritems():<br>+ for section, contents in self.sections.items():<br> if obj_type in contents:<br> return section<br> <br>diff --git a/lib/python/asterisk/realtime_odbc_module.py b/lib/python/asterisk/realtime_odbc_module.py<br>index 3653553..bbd8a8e 100644<br>--- a/lib/python/asterisk/realtime_odbc_module.py<br>+++ b/lib/python/asterisk/realtime_odbc_module.py<br>@@ -53,7 +53,7 @@<br> self.res_odbc = {}<br> <br> # generate configuration for each dsn<br>- for dsn, config in module_config.iteritems():<br>+ for dsn, config in module_config.items():<br> self._configure(dsn, config)<br> <br> # set the odbc and conf files<br>@@ -109,7 +109,7 @@<br> with open(filepath, 'w') as filehandle:<br> for section in contents:<br> filehandle.write('[' + section + ']\n')<br>- for name, value in contents[section].iteritems():<br>+ for name, value in contents[section].items():<br> filehandle.write(name + '=' + value + '\n')<br> <br> def _read_ini_file(self, filepath):<br>diff --git a/lib/python/asterisk/realtime_test_module.py b/lib/python/asterisk/realtime_test_module.py<br>index fd38aa9..da97422 100644<br>--- a/lib/python/asterisk/realtime_test_module.py<br>+++ b/lib/python/asterisk/realtime_test_module.py<br>@@ -91,7 +91,7 @@<br> <br> return [row for row in table<br> if all(key in row and re.match(value, row[key])<br>- for key, value in where.iteritems())]<br>+ for key, value in where.items())]<br> <br> def retrieve_rows(self, table_name, where):<br> """Retrieve multiple rows from a table.<br>@@ -239,7 +239,7 @@<br> since we could use a dict comprehension.<br> """<br> filtered_args = {}<br>- for key, values in args.iteritems():<br>+ for key, values in args.items():<br> if " LIKE" in key:<br> # Strip away " LIKE" and % from values<br> filtered_args[key[:-5]] = [val.replace('%', '.*')<br>@@ -250,7 +250,7 @@<br> LOGGER.debug('filtered args is %s' % filtered_args)<br> <br> return dict((key, values[0] if values else '.*') for key, values in<br>- filtered_args.iteritems())<br>+ filtered_args.items())<br> <br> def encode_row(self, row):<br> """Encode a retrieved row for an HTTP response.<br>@@ -261,7 +261,7 @@<br> Example output: 'foo=cat&bar=dog&baz=donkey'<br> """<br> string = '&'.join(['{0}={1}'.format(cgi.escape(key), cgi.escape(val))<br>- for key, val in row.iteritems()])<br>+ for key, val in row.items()])<br> LOGGER.debug("Returning response %s" % string)<br> return string<br> <br>@@ -481,7 +481,7 @@<br> if not data:<br> return<br> <br>- for table_name, rows in data.iteritems():<br>+ for table_name, rows in data.items():<br> self.rt_data.add_rows(table_name, rows)<br> <br> def setup_http(self):<br>diff --git a/lib/python/asterisk/self_test/harness_shared.py b/lib/python/asterisk/self_test/harness_shared.py<br>new file mode 100644<br>index 0000000..91449ac<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/harness_shared.py<br>@@ -0,0 +1,54 @@<br>+"""Unit test harness<br>+<br>+This module provides the entry-point for tests<br>+<br>+Copyright (C) 2018, CFWare, LLC.<br>+Corey Farrell <git@cfware.com><br>+<br>+This program is free software, distributed under the terms of<br>+the GNU General Public License Version 2.<br>+"""<br>+<br>+import logging<br>+import os<br>+import sys<br>+from twisted.internet import defer<br>+import unittest<br>+<br>+# Add directory where the modules to test can be found<br>+sys.path.append('lib/python')<br>+<br>+<br>+def ReadTestFile(filename, basepath="lib/python/asterisk/self_test"):<br>+ fd = open(os.path.join(basepath, filename), "r")<br>+ output = fd.read()<br>+ fd.close()<br>+ return output<br>+<br>+<br>+class AstMockOutput(object):<br>+ """mock cli output base class"""<br>+<br>+ def __init__(self, host="127.0.0.1"):<br>+ """Constructor"""<br>+ self.host = host<br>+<br>+ def MockDeferFile(self, filename):<br>+ return self.MockDefer(ReadTestFile(filename))<br>+<br>+ def MockDefer(self, output):<br>+ """use real defer to mock deferred output"""<br>+ self.output = output<br>+ deferred = defer.Deferred()<br>+ deferred.callback(self)<br>+ return deferred<br>+<br>+<br>+def main():<br>+ """Run the unit tests"""<br>+<br>+ logging.basicConfig()<br>+ unittest.main()<br>+<br>+<br>+__all__ = ["main", "AstMockOutput", "ReadTestFile"]<br>diff --git a/lib/python/asterisk/self_test/locks-backtrace.txt b/lib/python/asterisk/self_test/locks-backtrace.txt<br>new file mode 100644<br>index 0000000..0de89a4<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/locks-backtrace.txt<br>@@ -0,0 +1,20 @@<br>+=== ---> Lock #1 (astobj2.c): MUTEX 657 internal_ao2_callback c 0x2aaaac491f50 (1)<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_bt_get_addresses+0x1a) [0x4e9679]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ast_pthread_mutex_lock+0xf6) [0x4e22d9]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_lock+0x53) [0x4456fc]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x4464be]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_callback+0x59) [0x446a4e]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_find+0x2b) [0x446ba7]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x46d3a7]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_channel_get_by_name+0x24) [0x46d3e3]<br>+/usr/local/asterisk-1.8.6.0/lib/asterisk/modules/func_channel.so [0x2aaabfba2468]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_func_write+0x16a) [0x50aacd]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(pbx_builtin_setvar_helper+0x10e) [0x51fff4]<br>+/usr/local/asterisk-1.8.6.0/lib/asterisk/modules/chan_sip.so [0x2aaabe422d09]<br>+/usr/local/asterisk-1.8.6.0/lib/asterisk/modules/chan_sip.so [0x2aaabe4240a0]<br>+/usr/local/asterisk-1.8.6.0/lib/asterisk/modules/chan_sip.so [0x2aaabe423cf1]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_io_wait+0x1ba) [0x4dc2e4]<br>+/usr/local/asterisk-1.8.6.0/lib/asterisk/modules/chan_sip.so [0x2aaabe425722]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x5661c6]<br>+/lib64/libpthread.so.0 [0x3d1d80673d]<br>+/lib64/libc.so.6(clone+0x6d) [0x3d1ccd44bd]<br>diff --git a/lib/python/asterisk/self_test/locks-fail.txt b/lib/python/asterisk/self_test/locks-fail.txt<br>new file mode 100644<br>index 0000000..fb50ca8<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/locks-fail.txt<br>@@ -0,0 +1,52 @@<br>+=======================================================================<br>+=== Currently Held Locks ==============================================<br>+=======================================================================<br>+===<br>+=== <pending> <lock#> (<file>): <lock type> <line num> <function> <lock name> <lock addr> (times locked)<br>+===<br>+=== Thread ID: 0x402c6940 (do_monitor started at [25114] chan_sip.c restart_monitor())<br>+=== ---> Lock #0 (chan_sip.c): MUTEX 24629 handle_request_do &netlock 0x2aaabe671a40 (1)<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_bt_get_addresses+0x1a) [0x4e9679]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ast_pthread_mutex_lock+0xf6) [0x4e22d9]<br>+/usr/local/asterisk-1.8.6.0/lib/asterisk/modules/chan_sip.so [0x2aaabe423ee8]<br>+=== ---> Lock #1 (chan_sip.c): MUTEX 24629 handle_request_do &netlock 0x2aaabe671a40 (1)<br>+=== --- ---> Locked Here: channel.c line 4304 (ast_indicate_data)<br>+=== -------------------------------------------------------------------<br>+===<br>+=== Thread ID: 0x449ec940 (netconsole started at [ 1351] asterisk.c listener())<br>+=== ---> Waiting for Lock #0 (astobj2.c): MUTEX 842 internal_ao2_iterator_next a->c 0x2aaaac491f50 (1)<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_bt_get_addresses+0x1a) [0x4e9679]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ast_pthread_mutex_lock+0xf6) [0x4e22d9]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_lock+0x53) [0x4456fc]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x446cec]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_iterator_next+0x29) [0x447134]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_channel_iterator_next+0x19) [0x46cf7d]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x489e43]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_cli_command_full+0x222) [0x48eec4]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_cli_command_multiple_full+0x92) [0x48f035]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x43d129]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x5661c6]<br>+/lib64/libpthread.so.0 [0x3d1d80673d]<br>+/lib64/libc.so.6(clone+0x6d) [0x3d1ccd44bd]<br>+=== --- ---> Locked Here: astobj2.c line 657 (internal_ao2_callback)<br>+=== -------------------------------------------------------------------<br>+===<br>+=== Thread ID: 0x44a68940 (netconsole started at [ 1351] asterisk.c listener())<br>+=== ---> Waiting for Lock #0 (astobj2.c): MUTEX 842 internal_ao2_iterator_next a->c 0x2aaaac491f50 (1)<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_bt_get_addresses+0x1a) [0x4e9679]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ast_pthread_mutex_lock+0xf6) [0x4e22d9]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_lock+0x53) [0x4456fc]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x446cec]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_iterator_next+0x29) [0x447134]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_channel_iterator_next+0x19) [0x46cf7d]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x489e43]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_cli_command_full+0x222) [0x48eec4]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_cli_command_multiple_full+0x92) [0x48f035]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x43d129]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x5661c6]<br>+/lib64/libpthread.so.0 [0x3d1d80673d]<br>+/lib64/libc.so.6(clone+0x6d) [0x3d1ccd44bd]<br>+=== --- ---> Locked Here: astobj2.c line 657 (internal_ao2_callback)<br>+=== -------------------------------------------------------------------<br>+===<br>+=======================================================================<br>diff --git a/lib/python/asterisk/self_test/locks-large-multiple-object.txt b/lib/python/asterisk/self_test/locks-large-multiple-object.txt<br>new file mode 100644<br>index 0000000..ea657b6<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/locks-large-multiple-object.txt<br>@@ -0,0 +1,16 @@<br>+=== Thread ID: 0x449ec940 (netconsole started at [ 1351] asterisk.c listener())<br>+=== ---> Waiting for Lock #0 (astobj2.c): MUTEX 842 internal_ao2_iterator_next a->c 0x2aaaac491f50 (1)<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_bt_get_addresses+0x1a) [0x4e9679]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ast_pthread_mutex_lock+0xf6) [0x4e22d9]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_lock+0x53) [0x4456fc]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x446cec]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ao2_iterator_next+0x29) [0x447134]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_channel_iterator_next+0x19) [0x46cf7d]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x489e43]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_cli_command_full+0x222) [0x48eec4]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_cli_command_multiple_full+0x92) [0x48f035]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x43d129]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk [0x5661c6]<br>+/lib64/libpthread.so.0 [0x3d1d80673d]<br>+/lib64/libc.so.6(clone+0x6d) [0x3d1ccd44bd]<br>+=== --- ---> Locked Here: astobj2.c line 657 (internal_ao2_callback)<br>diff --git a/lib/python/asterisk/self_test/locks-multiple-objects-no-backtrace.txt b/lib/python/asterisk/self_test/locks-multiple-objects-no-backtrace.txt<br>new file mode 100644<br>index 0000000..3ed0ca5<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/locks-multiple-objects-no-backtrace.txt<br>@@ -0,0 +1,5 @@<br>+=== Thread ID: 0x402c6940 (do_monitor started at [25114] chan_sip.c restart_monitor())<br>+=== ---> Lock #0 (chan_sip.c): MUTEX 24629 handle_request_do &netlock 0x2aaabe671a40 (1)<br>+=== ---> Lock #1 (astobj2.c): MUTEX 657 internal_ao2_callback c 0x2aaaac491f50 (1)<br>+=== ---> Waiting for Lock #2 (channel.c): MUTEX 1691 ast_channel_cmp_cb chan 0x2aaaacd3a4e0 (1)<br>+=== --- ---> Locked Here: channel.c line 4304 (ast_indicate_data)<br>diff --git a/lib/python/asterisk/self_test/locks-pass.txt b/lib/python/asterisk/self_test/locks-pass.txt<br>new file mode 100644<br>index 0000000..bbb3b92<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/locks-pass.txt<br>@@ -0,0 +1,8 @@<br>+=======================================================================<br>+=== Currently Held Locks ==============================================<br>+=======================================================================<br>+===<br>+=== <pending> <lock#> (<file>): <lock type> <line num> <function> <lock name> <lock addr> (times locked)<br>+===<br>+===<br>+=======================================================================<br>diff --git a/lib/python/asterisk/self_test/locks-single-object-no-held-info.txt b/lib/python/asterisk/self_test/locks-single-object-no-held-info.txt<br>new file mode 100644<br>index 0000000..e1bf47a<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/locks-single-object-no-held-info.txt<br>@@ -0,0 +1,11 @@<br>+=== Thread ID: 0x7f668c142700 (do_monitor started at [25915] chan_sip.c restart_monitor())<br>+=== ---> Lock #0 (chan_sip.c): MUTEX 25390 handle_request_do &netlock 0x7f6652193900 (1)<br>+main/logger.c:1302 ast_bt_get_addresses() (0x505e53+1D)<br>+main/lock.c:193 __ast_pthread_mutex_lock() (0x4fe55c+D9)<br>+channels/chan_sip.c:25393 handle_request_do()<br>+channels/chan_sip.c:25352 sipsock_read()<br>+main/io.c:288 ast_io_wait() (0x4f8228+19C)<br>+channels/chan_sip.c:25882 do_monitor()<br>+main/utils.c:1010 dummy_start()<br>+libpthread.so.0 <unknown>()<br>+libc.so.6 clone() (0x31be0e0bc0+6D)<br>diff --git a/lib/python/asterisk/self_test/locks-single-object.txt b/lib/python/asterisk/self_test/locks-single-object.txt<br>new file mode 100644<br>index 0000000..db356ed<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/locks-single-object.txt<br>@@ -0,0 +1,6 @@<br>+=== Thread ID: 0x402c6940 (do_monitor started at [25114] chan_sip.c restart_monitor())<br>+=== ---> Lock #0 (chan_sip.c): MUTEX 24629 handle_request_do &netlock 0x2aaabe671a40 (1)<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(ast_bt_get_addresses+0x1a) [0x4e9679]<br>+/usr/local/asterisk-1.8.6.0/sbin/asterisk(__ast_pthread_mutex_lock+0xf6) [0x4e22d9]<br>+/usr/local/asterisk-1.8.6.0/lib/asterisk/modules/chan_sip.so [0x2aaabe423ee8]<br>+=== --- ---> Locked Here: channel.c line 4304 (ast_indicate_data)<br>diff --git a/lib/python/asterisk/self_test/test_buildoptions.py b/lib/python/asterisk/self_test/test_buildoptions.py<br>new file mode 100755<br>index 0000000..1f4ca77<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/test_buildoptions.py<br>@@ -0,0 +1,26 @@<br>+#!/usr/bin/env python<br>+"""Asterisk Build Options Handling Unit Test<br>+<br>+Copyright (C) 2011-2012, Digium, Inc.<br>+Matt Jordan <mjordan@digium.com><br>+<br>+This program is free software, distributed under the terms of<br>+the GNU General Public License Version 2.<br>+"""<br>+<br>+from harness_shared import main<br>+import unittest<br>+from asterisk.buildoptions import AsteriskBuildOptions<br>+<br>+<br>+class AsteriskBuildOptionsTests(unittest.TestCase):<br>+ """Unit tests for AsteriskBuildOptions"""<br>+<br>+ def test_1(self):<br>+ """Test the defaults paths"""<br>+ build_options = AsteriskBuildOptions()<br>+ self.assertTrue(build_options)<br>+<br>+<br>+if __name__ == "__main__":<br>+ main()<br>diff --git a/lib/python/asterisk/self_test/test_cdr.py b/lib/python/asterisk/self_test/test_cdr.py<br>new file mode 100755<br>index 0000000..251530b<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/test_cdr.py<br>@@ -0,0 +1,44 @@<br>+#!/usr/bin/env python<br>+"""Asterisk call detail record unit tests<br>+<br>+This module implements an Asterisk CDR parser.<br>+<br>+Copyright (C) 2010, Digium, Inc.<br>+Terry Wilson<twilson@digium.com><br>+<br>+This program is free software, distributed under the terms of<br>+the GNU General Public License Version 2.<br>+"""<br>+<br>+from harness_shared import main<br>+import unittest<br>+from asterisk.cdr import AsteriskCSVCDR, AsteriskCSVCDRLine<br>+<br>+<br>+class AsteriskCSVCDRTests(unittest.TestCase):<br>+ """Unit tests for AsteriskCSVCDR"""<br>+<br>+ def test_cdr(self):<br>+ """Test the self_test/Master.csv record"""<br>+<br>+ cdr = AsteriskCSVCDR("lib/python/asterisk/self_test/Master.csv")<br>+ self.assertEqual(len(cdr), 2)<br>+ self.assertTrue(<br>+ AsteriskCSVCDRLine(duration=7, lastapp="hangup").match(<br>+ cdr[0],<br>+ exact=(True, True)))<br>+ self.assertTrue(cdr[0].match(<br>+ AsteriskCSVCDRLine(duration=7, lastapp="hangup"),<br>+ exact=(True, True)))<br>+<br>+ self.assertFalse(cdr[1].match(cdr[0], silent=True, exact=(True, True)))<br>+ self.assertFalse(cdr[0].match(cdr[1], silent=True, exact=(True, True)))<br>+ self.assertEqual(cdr[0].billsec, "7")<br>+<br>+ self.assertTrue(cdr.match(cdr))<br>+ cdr2 = AsteriskCSVCDR("lib/python/asterisk/self_test/Master2.csv")<br>+ self.assertFalse(cdr.match(cdr2))<br>+<br>+<br>+if __name__ == '__main__':<br>+ main()<br>diff --git a/lib/python/asterisk/self_test/test_cel.py b/lib/python/asterisk/self_test/test_cel.py<br>new file mode 100755<br>index 0000000..3ea8aa9<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/test_cel.py<br>@@ -0,0 +1,47 @@<br>+#!/usr/bin/env python<br>+"""Asterisk call detail record unit tests<br>+<br>+This module implements an Asterisk CDR parser.<br>+<br>+Copyright (C) 2010, Digium, Inc.<br>+Terry Wilson<twilson@digium.com><br>+<br>+This program is free software, distributed under the terms of<br>+the GNU General Public License Version 2.<br>+"""<br>+<br>+from harness_shared import main<br>+import unittest<br>+from asterisk.cel import AsteriskCSVCEL, AsteriskCSVCELLine<br>+<br>+<br>+class AsteriskCSVCELTests(unittest.TestCase):<br>+ """Unit tests for AsteriskCSVCEL"""<br>+<br>+ def test_cel(self):<br>+ """Test CEL using self_test/CELMaster1.csv"""<br>+<br>+ cel = AsteriskCSVCEL("lib/python/asterisk/self_test/CELMaster1.csv")<br>+ self.assertEqual(len(cel), 16)<br>+ self.assertTrue(AsteriskCSVCELLine(<br>+ eventtype="LINKEDID_END",<br>+ channel="TinCan/string").match(cel[-1],<br>+ silent=True,<br>+ exact=(True, True)))<br>+ self.assertTrue(cel[-1].match(<br>+ AsteriskCSVCELLine(eventtype="LINKEDID_END",<br>+ channel="TinCan/string"),<br>+ silent=True,<br>+ exact=(True, True)))<br>+<br>+ self.assertFalse(cel[1].match(cel[0], silent=True, exact=(True, True)))<br>+ self.assertFalse(cel[0].match(cel[1], silent=True, exact=(True, True)))<br>+ self.assertEqual(cel[-1].channel, "TinCan/string")<br>+<br>+ self.assertTrue(cel.match(cel))<br>+ cel2 = AsteriskCSVCEL("lib/python/asterisk/self_test/CELMaster2.csv")<br>+ self.assertFalse(cel.match(cel2))<br>+<br>+<br>+if __name__ == '__main__':<br>+ main()<br>diff --git a/lib/python/asterisk/self_test/test_channel_test_condition.py b/lib/python/asterisk/self_test/test_channel_test_condition.py<br>new file mode 100755<br>index 0000000..e32d883<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/test_channel_test_condition.py<br>@@ -0,0 +1,144 @@<br>+#!/usr/bin/env python<br>+"""Tests for test condition for channels<br>+<br>+Copyright (C) 2011-2012, Digium, Inc.<br>+Matt Jordan <mjordan@digium.com><br>+<br>+This program is free software, distributed under the terms of<br>+the GNU General Public License Version 2.<br>+"""<br>+<br>+from harness_shared import AstMockOutput, main<br>+import unittest<br>+from asterisk.channel_test_condition import ChannelTestCondition<br>+<br>+<br>+class AstMockObjectInactive(AstMockOutput):<br>+ """mock cli output showing no active channels"""<br>+<br>+ def cli_exec(self, command):<br>+ """presume command is core show channels and generate output"""<br>+ output = ""<br>+ output += "Channel Location State Application(Data)\n"<br>+ output += "0 active channels\n"<br>+ output += "0 active calls\n"<br>+ output += "2 calls processed\n"<br>+ output += "Asterisk ending (0).\n"<br>+ return self.MockDefer(output)<br>+<br>+<br>+class AstMockObjectSingle(AstMockOutput):<br>+ """mock cli output showing single active channel"""<br>+<br>+ def cli_exec(self, command):<br>+ """presume command is core show channels and generate output"""<br>+ output = ""<br>+ output += "Channel Location State Application(Data)\n"<br>+ output += "Local/123@default-00 (None) Down ()\n"<br>+ output += "1 active channels\n"<br>+ output += "0 active calls\n"<br>+ output += "2 calls processed\n"<br>+ output += "Asterisk ending (0).\n"<br>+ return self.MockDefer(output)<br>+<br>+<br>+class AstMockObjectMultiple(AstMockOutput):<br>+ """mock cli output showing multiple active channels"""<br>+<br>+ def cli_exec(self, command):<br>+ """presume command is core show channels and generate output"""<br>+ output = ""<br>+ output += "Channel Location State Application(Data)\n"<br>+ output += "PJSIP/123@default-00 (None) Down ()\n"<br>+ output += "Local/123@default-00 (None) Down ()\n"<br>+ output += "SIP/alice@default-00 (None) Down ()\n"<br>+ output += "3 active channels\n"<br>+ output += "0 active calls\n"<br>+ output += "2 calls processed\n"<br>+ output += "Asterisk ending (0).\n"<br>+ return self.MockDefer(output)<br>+<br>+<br>+class AstMockObjectLeaked(AstMockOutput):<br>+ """mock cli output showing leaked channel"""<br>+<br>+ def cli_exec(self, command):<br>+ """presume command is core show channels and generate output"""<br>+ output = ""<br>+ output += "Channel Location State Application(Data)\n"<br>+ output += "Local/123@default-00 (None) Down ()\n"<br>+ output += "0 active channels\n"<br>+ output += "0 active calls\n"<br>+ output += "2 calls processed\n"<br>+ output += "Asterisk ending (0).\n"<br>+ return self.MockDefer(output)<br>+<br>+<br>+class TestConfig(object):<br>+ """Fake TestConfig object for unittest"""<br>+<br>+ def __init__(self):<br>+ self.class_type_name = "bogus"<br>+ self.config = {}<br>+ self.enabled = True<br>+ self.pass_expected = True<br>+<br>+<br>+class ChannelTestConditionUnitTest(unittest.TestCase):<br>+ """Unit Tests for ChannelTestCondition"""<br>+<br>+ def test_evaluate_inactive(self):<br>+ """test inactive channel condition"""<br>+ obj = ChannelTestCondition(TestConfig())<br>+ obj.register_asterisk_instance(AstMockObjectInactive())<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Passed')<br>+<br>+ def test_evaluate_multiple_fail(self):<br>+ """test multiple channel condition"""<br>+ obj = ChannelTestCondition(TestConfig())<br>+ obj.register_asterisk_instance(AstMockObjectMultiple())<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Failed')<br>+<br>+ def test_evaluate_multiple_fail2(self):<br>+ """test multiple channel condition"""<br>+ obj = ChannelTestCondition(TestConfig())<br>+ obj.allowed_channels = 2<br>+ obj.register_asterisk_instance(AstMockObjectMultiple())<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Failed')<br>+<br>+ def test_evaluate_multiple_pass(self):<br>+ """test multiple channel condition"""<br>+ obj = ChannelTestCondition(TestConfig())<br>+ obj.allowed_channels = 3<br>+ obj.register_asterisk_instance(AstMockObjectMultiple())<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Passed')<br>+<br>+ def test_evaluate_single_fail(self):<br>+ """test single channel condition"""<br>+ obj = ChannelTestCondition(TestConfig())<br>+ obj.register_asterisk_instance(AstMockObjectSingle())<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Failed')<br>+<br>+ def test_evaluate_single_pass(self):<br>+ """test single channel condition"""<br>+ obj = ChannelTestCondition(TestConfig())<br>+ obj.allowed_channels = 1<br>+ obj.register_asterisk_instance(AstMockObjectSingle())<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Passed')<br>+<br>+ def test_evaluate_leaked(self):<br>+ """test leaked channel condition"""<br>+ obj = ChannelTestCondition(TestConfig())<br>+ obj.register_asterisk_instance(AstMockObjectLeaked())<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Failed')<br>+<br>+<br>+if __name__ == "__main__":<br>+ main()<br>diff --git a/lib/python/asterisk/self_test/test_config.py b/lib/python/asterisk/self_test/test_config.py<br>new file mode 100755<br>index 0000000..cc88636<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/test_config.py<br>@@ -0,0 +1,83 @@<br>+#!/usr/bin/env python<br>+"""Asterisk Configuration File Handling Unit Tests.<br>+<br>+Copyright (C) 2010, Digium, Inc.<br>+Russell Bryant <russell@digium.com><br>+<br>+This program is free software, distributed under the terms of<br>+the GNU General Public License Version 2.<br>+"""<br>+<br>+from harness_shared import main<br>+import unittest<br>+from asterisk.config import ConfigFile<br>+<br>+<br>+class ConfigFileTests(unittest.TestCase):<br>+ """Unit tests for ConfigFile"""<br>+<br>+ def test_conf(self):<br>+ """Test parsing a blob of config data"""<br>+ test = \<br>+ "; stuff\n" \<br>+ "this line is invalid on purpose\n" \<br>+ "[this is] also invalid]\n" \<br>+ ";-- comment --;\n" \<br>+ ";-- \n" \<br>+ "[this is commented out]\n" \<br>+ " --;\n" \<br>+ "[foo]\n" \<br>+ "a = b\n" \<br>+ " b = a \n" \<br>+ "this line is invalid on purpose\n" \<br>+ ";moo\n" \<br>+ "c = d;asdadf;adfads;adsfasdf\n" \<br>+ " [bar] ;asdfasdf\n" \<br>+ "a-b=c-d\n" \<br>+ "xyz=x|y|z\n" \<br>+ "1234 => 4242,Example Mailbox,root@localhost,,var=val\n" \<br>+ "\n" \<br>+ "[template](!)\n" \<br>+ "foo=bar\n" \<br>+ "exten => _NXX.,n,Wait(1)\n" \<br>+ "astetcdir => /etc/asterisk\n"<br>+<br>+ conf = ConfigFile(filename=None, config_str=test)<br>+<br>+ self.assertEqual(len(conf.categories), 3)<br>+<br>+ self.assertEqual(conf.categories[0].name, "foo")<br>+ self.assertFalse(conf.categories[0].template)<br>+ self.assertEqual(len(conf.categories[0].options), 3)<br>+ self.assertEqual(conf.categories[0].options[0][0], "a")<br>+ self.assertEqual(conf.categories[0].options[0][1], "b")<br>+ self.assertEqual(conf.categories[0].options[1][0], "b")<br>+ self.assertEqual(conf.categories[0].options[1][1], "a")<br>+ self.assertEqual(conf.categories[0].options[2][0], "c")<br>+ self.assertEqual(conf.categories[0].options[2][1], "d")<br>+<br>+ self.assertEqual(conf.categories[1].name, "bar")<br>+ self.assertFalse(conf.categories[1].template)<br>+ self.assertEqual(len(conf.categories[1].options), 3)<br>+ self.assertEqual(conf.categories[1].options[0][0], "a-b")<br>+ self.assertEqual(conf.categories[1].options[0][1], "c-d")<br>+ self.assertEqual(conf.categories[1].options[1][0], "xyz")<br>+ self.assertEqual(conf.categories[1].options[1][1], "x|y|z")<br>+ self.assertEqual(conf.categories[1].options[2][0], "1234")<br>+ self.assertEqual(conf.categories[1].options[2][1],<br>+ "4242,Example Mailbox,root@localhost,,var=val")<br>+<br>+ self.assertEqual(conf.categories[2].name, "template")<br>+ self.assertTrue(conf.categories[2].template)<br>+ self.assertEqual(len(conf.categories[2].options), 3)<br>+ self.assertEqual(conf.categories[2].options[0][0], "foo")<br>+ self.assertEqual(conf.categories[2].options[0][1], "bar")<br>+ self.assertEqual(conf.categories[2].options[1][0], "exten")<br>+ self.assertEqual(conf.categories[2].options[1][1],<br>+ "_NXX.,n,Wait(1)")<br>+ self.assertEqual(conf.categories[2].options[2][0], "astetcdir")<br>+ self.assertEqual(conf.categories[2].options[2][1], "/etc/asterisk")<br>+<br>+<br>+if __name__ == "__main__":<br>+ main()<br>diff --git a/lib/python/asterisk/self_test/test_lock_test_condition.py b/lib/python/asterisk/self_test/test_lock_test_condition.py<br>new file mode 100755<br>index 0000000..6cda06a<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/test_lock_test_condition.py<br>@@ -0,0 +1,193 @@<br>+#!/usr/bin/env python<br>+"""Held locks test condition unit tests<br>+<br>+Copyright (C) 2011-2012, Digium, Inc.<br>+Matt Jordan <mjordan@digium.com><br>+<br>+This program is free software, distributed under the terms of<br>+the GNU General Public License Version 2.<br>+"""<br>+<br>+from harness_shared import AstMockOutput, ReadTestFile, main<br>+import unittest<br>+from asterisk.lock_test_condition import LockSequence, LockObject, LockTestCondition<br>+<br>+<br>+class AstMockObjectPassed(AstMockOutput):<br>+ """A lock output that passed"""<br>+<br>+ def __init__(self):<br>+ """Constructor"""<br>+ self.host = "127.0.0.2"<br>+<br>+ def cli_exec(self, command):<br>+ """Fake out a CLI command execution"""<br>+ return self.MockDeferFile("locks-pass.txt")<br>+<br>+<br>+class AstMockObjectFailure(AstMockOutput):<br>+ """A lock object that failed"""<br>+<br>+ def cli_exec(self, command):<br>+ """Fake out a CLI command execution"""<br>+ return self.MockDeferFile("locks-fail.txt")<br>+<br>+<br>+class TestConfig(object):<br>+ """Fake TestConfig object"""<br>+<br>+ def __init__(self):<br>+ """ Values here don't matter much - we just need to have something """<br>+ self.class_type_name = "asterisk.LockTestCondition.LockTestCondition"<br>+ self.pass_expected = True<br>+ self.type = "Post"<br>+ self.related_condition = ""<br>+ self.config = {}<br>+ self.enabled = True<br>+<br>+<br>+class LockTestConditionUnitTest(unittest.TestCase):<br>+ """Unit tests for LockTestCondition"""<br>+<br>+ def test_evaluate_failed(self):<br>+ """Test a failed locking condition"""<br>+ ast = AstMockObjectFailure()<br>+ obj = LockTestCondition(TestConfig())<br>+ obj.register_asterisk_instance(ast)<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Failed')<br>+<br>+ def test_evaluate_pass(self):<br>+ """Test a passed locking condition"""<br>+ ast = AstMockObjectPassed()<br>+ obj = LockTestCondition(TestConfig())<br>+ obj.register_asterisk_instance(ast)<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Passed')<br>+<br>+ def test_evaluate_multiple(self):<br>+ """Test multiple results"""<br>+ ast1 = AstMockObjectPassed()<br>+ ast2 = AstMockObjectFailure()<br>+ obj = LockTestCondition(TestConfig())<br>+ obj.register_asterisk_instance(ast1)<br>+ obj.register_asterisk_instance(ast2)<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Failed')<br>+<br>+<br>+class LockSequenceUnitTest(unittest.TestCase):<br>+ """Tests for parsing a lock sequence"""<br>+<br>+ def test_single_object_no_held_info(self):<br>+ """Test a lock sequence with no waiting lock"""<br>+<br>+ obj = LockSequence()<br>+ obj.parse_lock_sequence(ReadTestFile("locks-single-object-no-held-info.txt"))<br>+<br>+ def test_large_multiple_object(self):<br>+ """Test with a waiting lock"""<br>+<br>+ obj = LockSequence()<br>+ obj.parse_lock_sequence(ReadTestFile("locks-large-multiple-object.txt"))<br>+ self.assertEqual(obj.thread_id, "0x449ec940")<br>+ self.assertEqual(obj.thread_name, "netconsole")<br>+ self.assertEqual(obj.thread_line, 1351)<br>+ self.assertEqual(obj.thread_file, "asterisk.c")<br>+ self.assertEqual(obj.thread_func, "listener")<br>+ self.assertTrue(len(obj.locks) == 1)<br>+ self.assertEqual(obj.locks[0].locked_file, "astobj2.c")<br>+ self.assertEqual(obj.locks[0].locked_line, 657)<br>+ self.assertEqual(obj.locks[0].locked_func, "internal_ao2_callback")<br>+<br>+ def test_single_object(self):<br>+ """Test a lock held somewhere else"""<br>+<br>+ obj = LockSequence()<br>+ obj.parse_lock_sequence(ReadTestFile("locks-single-object.txt"))<br>+ self.assertEqual(obj.thread_id, "0x402c6940")<br>+ self.assertEqual(obj.thread_name, "do_monitor")<br>+ self.assertEqual(obj.thread_line, 25114)<br>+ self.assertEqual(obj.thread_file, "chan_sip.c")<br>+ self.assertEqual(obj.thread_func, "restart_monitor")<br>+ self.assertTrue(len(obj.locks) == 1)<br>+ self.assertEqual(obj.locks[0].locked_file, "channel.c")<br>+ self.assertEqual(obj.locks[0].locked_line, 4304)<br>+ self.assertEqual(obj.locks[0].locked_func, "ast_indicate_data")<br>+ self.assertEqual(obj.locks[0].id, 0)<br>+ self.assertEqual(obj.locks[0].type, "MUTEX")<br>+ self.assertEqual(obj.locks[0].file, "chan_sip.c")<br>+ self.assertEqual(obj.locks[0].line_number, 24629)<br>+ self.assertEqual(obj.locks[0].func, "handle_request_do")<br>+ self.assertEqual(obj.locks[0].name, "&netlock")<br>+ self.assertEqual(obj.locks[0].addr, "0x2aaabe671a40")<br>+ self.assertEqual(obj.locks[0].lock_count, 1)<br>+ self.assertTrue(obj.locks[0].held)<br>+ self.assertTrue(len(obj.locks[0].backtrace) == 3)<br>+<br>+ def test_multiple_objects_no_backtrace(self):<br>+ """Test multiple locks with no backtrace"""<br>+<br>+ obj = LockSequence()<br>+ obj.parse_lock_sequence(ReadTestFile("locks-multiple-objects-no-backtrace.txt"))<br>+ self.assertEqual(obj.thread_id, "0x402c6940")<br>+ self.assertEqual(obj.thread_name, "do_monitor")<br>+ self.assertEqual(obj.thread_line, 25114)<br>+ self.assertEqual(obj.thread_file, "chan_sip.c")<br>+ self.assertEqual(obj.thread_func, "restart_monitor")<br>+ self.assertTrue(len(obj.locks) == 3)<br>+ self.assertEqual(obj.locks[2].locked_file, "channel.c")<br>+ self.assertEqual(obj.locks[2].locked_line, 4304)<br>+ self.assertEqual(obj.locks[2].locked_func, "ast_indicate_data")<br>+ self.assertEqual(obj.locks[0].id, 0)<br>+ self.assertEqual(obj.locks[0].type, "MUTEX")<br>+ self.assertEqual(obj.locks[0].file, "chan_sip.c")<br>+ self.assertEqual(obj.locks[0].line_number, 24629)<br>+ self.assertEqual(obj.locks[0].func, "handle_request_do")<br>+ self.assertEqual(obj.locks[0].name, "&netlock")<br>+ self.assertEqual(obj.locks[0].addr, "0x2aaabe671a40")<br>+ self.assertEqual(obj.locks[0].lock_count, 1)<br>+ self.assertTrue(obj.locks[0].held)<br>+ self.assertTrue(len(obj.locks[0].backtrace) == 0)<br>+<br>+<br>+class LockObjectUnitTest(unittest.TestCase):<br>+ """Unit tests for LockObject"""<br>+<br>+ def test_no_backtrace(self):<br>+ """Test creating a lock object with no thread backtrace"""<br>+<br>+ lock_line = "=== ---> Waiting for Lock #0 (sig_ss7.c): " + \<br>+ "MUTEX 636 ss7_linkset &linkset->lock 0x2aaab8a6b588 (1)"<br>+ obj = LockObject()<br>+ obj.parse_lock_information(lock_line)<br>+ self.assertEqual(obj.id, 0)<br>+ self.assertEqual(obj.type, "MUTEX")<br>+ self.assertEqual(obj.file, "sig_ss7.c")<br>+ self.assertEqual(obj.line_number, 636)<br>+ self.assertEqual(obj.func, "ss7_linkset")<br>+ self.assertEqual(obj.name, "&linkset->lock")<br>+ self.assertEqual(obj.addr, "0x2aaab8a6b588")<br>+ self.assertEqual(obj.lock_count, 1)<br>+ self.assertFalse(obj.held)<br>+ self.assertTrue(len(obj.backtrace) == 0)<br>+<br>+ def test_with_backtrace(self):<br>+ """Test creating a lock object with a thread backtrace"""<br>+<br>+ obj = LockObject()<br>+ obj.parse_lock_information(ReadTestFile("locks-backtrace.txt"))<br>+ self.assertEqual(obj.id, 1)<br>+ self.assertEqual(obj.type, "MUTEX")<br>+ self.assertEqual(obj.file, "astobj2.c")<br>+ self.assertEqual(obj.line_number, 657)<br>+ self.assertEqual(obj.func, "internal_ao2_callback")<br>+ self.assertEqual(obj.name, "c")<br>+ self.assertEqual(obj.addr, "0x2aaaac491f50")<br>+ self.assertEqual(obj.lock_count, 1)<br>+ self.assertTrue(obj.held)<br>+ self.assertTrue(len(obj.backtrace) == 19)<br>+<br>+<br>+if __name__ == "__main__":<br>+ main()<br>diff --git a/lib/python/asterisk/self_test/test2_matcher.py b/lib/python/asterisk/self_test/test_matcher.py<br>similarity index 100%<br>rename from lib/python/asterisk/self_test/test2_matcher.py<br>rename to lib/python/asterisk/self_test/test_matcher.py<br>diff --git a/lib/python/asterisk/self_test/test_sip_dialog_test_condition.py.txt b/lib/python/asterisk/self_test/test_sip_dialog_test_condition.py.txt<br>new file mode 100644<br>index 0000000..717e183<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/test_sip_dialog_test_condition.py.txt<br>@@ -0,0 +1,426 @@<br>+#!/usr/bin/env python<br>+"""Test condition for verifying SIP dialogs unit tests<br>+<br>+Copyright (C) 2011-2012, Digium, Inc.<br>+Matt Jordan <mjordan@digium.com><br>+<br>+This program is free software, distributed under the terms of<br>+the GNU General Public License Version 2.<br>+"""<br>+<br>+from harness_shared import AstMockOutput, main<br>+import unittest<br>+from asterisk.sip_dialog_test_condition import SipDialogPreTestCondition, \<br>+ SipDialogPostTestCondition<br>+<br>+<br>+class TestConfig(object):<br>+ """Mock TestConfig object"""<br>+<br>+ def __init__(self):<br>+ """Constructor<br>+<br>+ Values here don't matter much - we just need to have something"""<br>+ self.type_name = ("asterisk.sip_dialog_test_condition." +<br>+ "SipDialogPostTestCondition")<br>+ self.pass_expected = True<br>+ self.type = "Post"<br>+ self.related_condition = ""<br>+ self.class_type_name = "sip_dialog_test_condition"<br>+ self.config = {}<br>+ self.enabled = True<br>+<br>+<br>+class TestConfigWithHistory(TestConfig):<br>+ """Mock TestConfig object with history requirements"""<br>+<br>+ def __init__(self):<br>+ """Constructor"""<br>+ super(TestConfigWithHistory, self).__init__()<br>+<br>+ self.config['history_requirements'] = []<br>+ self.config['history_requirements'].append('Hangup')<br>+ self.config['history_requirements'].append('NewChan')<br>+<br>+<br>+class AstMockObjectPostTestNoDestructionFail(AstMockOutput):<br>+ """Mock out CLI execution from Asterisk instance<br>+<br>+ This mock object makes it appear as if a dialog failed to be destroyed<br>+ """<br>+ def __init__(self):<br>+ """Constructor"""<br>+ self.host = "127.0.0.6"<br>+<br>+ def cli_exec(self, command):<br>+ """Mock CLI execution/response"""<br>+<br>+ output = ""<br>+ if command == "sip show objects":<br>+ output = "-= Peer objects: 4 static, 0 realtime, 0 autocreate =-\n\n"<br>+ output += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7001\ntype: peer\nobjflags: 0\nrefcount: 1\n\n"<br>+ output += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "-= Peer objects by IP =-\n\n"<br>+ output += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "-= Registry objects: 0 =-\n\n"<br>+ output += "-= Dialog objects:\n\n"<br>+ output += "name: 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060\n"<br>+ output += "type: dialog\n"<br>+ output += "objflags: 0\n"<br>+ output += "refcount: 2\n\n"<br>+ output += "name: 2ec048aa4ed1239664f6408f0c5044c5@127.0.0.2:5060\n"<br>+ output += "type: dialog\n"<br>+ output += "objflags: 0\n"<br>+ output += "refcount: 2\n\n"<br>+ elif command == "sip show history 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060":<br>+ output = "* SIP Call\n"<br>+ output += "1. NewChan Channel SIP/ast1-00000002 - from 2ec048aa4ed1239664f6408f0c5044\n"<br>+ output += "2. TxReqRel INVITE / 102 INVITE - INVITE\n"<br>+ output += "3. Rx SIP/2.0 / 102 INVITE / 100 Trying\n"<br>+ output += "4. Rx SIP/2.0 / 102 INVITE / 200 OK\n"<br>+ output += "5. TxReq ACK / 102 ACK - ACK\n"<br>+ output += "6. Rx BYE / 102 BYE / sip:ast2@127.0.0.2:5060\n"<br>+ output += "7. RTCPaudio Quality:ssrc=28249381;themssrc=485141946;lp=0;rxjitter=0.000029\n"<br>+ output += "8. RTCPaudioJitter Quality:minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0\n"<br>+ output += "9. RTCPaudioLoss Quality:minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.00000\n"<br>+ output += "10. RTCPaudioRTT Quality:minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrt\n"<br>+ output += "11. SchedDestroy 32000 ms\n"<br>+ output += "12. TxResp SIP/2.0 / 102 BYE - 200 OK\n"<br>+ output += "13. Hangup Cause Normal Clearing\n"<br>+ elif command == "sip show history 2ec048aa4ed1239664f6408f0c5044c5@127.0.0.2:5060":<br>+ output = "* SIP Call\n"<br>+ output += "1. NewChan Channel SIP/ast1-00000002 - from 2ec048aa4ed1239664f6408f0c5044\n"<br>+ output += "2. TxReqRel INVITE / 102 INVITE - INVITE\n"<br>+ output += "3. Rx SIP/2.0 / 102 INVITE / 100 Trying\n"<br>+ output += "4. Rx SIP/2.0 / 102 INVITE / 200 OK\n"<br>+ output += "5. TxReq ACK / 102 ACK - ACK\n"<br>+ output += "6. Rx BYE / 102 BYE / sip:ast2@127.0.0.2:5060\n"<br>+ output += "7. RTCPaudio Quality:ssrc=28249381;themssrc=485141946;lp=0;rxjitter=0.000029\n"<br>+ output += "8. RTCPaudioJitter Quality:minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0\n"<br>+ output += "9. RTCPaudioLoss Quality:minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.00000\n"<br>+ output += "10. RTCPaudioRTT Quality:minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrt\n"<br>+ output += "11. TxResp SIP/2.0 / 102 BYE - 200 OK\n"<br>+ output += "12. Hangup Cause Normal Clearing\n"<br>+ return self.MockDefer(output)<br>+<br>+<br>+class AstMockObjectPostTestNoHangupFail(AstMockOutput):<br>+ """Mock out CLI execution from Asterisk instance<br>+<br>+ This mock object makes it appear as if a channel failed to hangup<br>+ """<br>+<br>+ def __init__(self):<br>+ """Constructor"""<br>+ self.host = "127.0.0.5"<br>+<br>+ def cli_exec(self, command):<br>+ """Mock CLI execution/response"""<br>+<br>+ output = ""<br>+ if command == "sip show objects":<br>+ output = "-= Peer objects: 4 static, 0 realtime, 0 autocreate =-\n\n"<br>+ output += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7001\ntype: peer\nobjflags: 0\nrefcount: 1\n\n"<br>+ output += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "-= Peer objects by IP =-\n\n"<br>+ output += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "-= Registry objects: 0 =-\n\n"<br>+ output += "-= Dialog objects:\n\n"<br>+ output += "name: 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060\n"<br>+ output += "type: dialog\n"<br>+ output += "objflags: 0\n"<br>+ output += "refcount: 2\n\n"<br>+ output += "name: 2ec048aa4ed1239664f6408f0c5044c5@127.0.0.2:5060\n"<br>+ output += "type: dialog\n"<br>+ output += "objflags: 0\n"<br>+ output += "refcount: 2\n\n"<br>+ elif command == "sip show history 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060":<br>+ output = "* SIP Call\n"<br>+ output += "1. NewChan Channel SIP/ast1-00000002 - from 2ec048aa4ed1239664f6408f0c5044\n"<br>+ output += "2. TxReqRel INVITE / 102 INVITE - INVITE\n"<br>+ output += "3. Rx SIP/2.0 / 102 INVITE / 100 Trying\n"<br>+ output += "4. Rx SIP/2.0 / 102 INVITE / 200 OK\n"<br>+ output += "5. TxReq ACK / 102 ACK - ACK\n"<br>+ output += "6. Rx BYE / 102 BYE / sip:ast2@127.0.0.2:5060\n"<br>+ output += "7. RTCPaudio Quality:ssrc=28249381;themssrc=485141946;lp=0;rxjitter=0.000029\n"<br>+ output += "8. RTCPaudioJitter Quality:minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0\n"<br>+ output += "9. RTCPaudioLoss Quality:minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.00000\n"<br>+ output += "10. RTCPaudioRTT Quality:minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrt\n"<br>+ output += "11. SchedDestroy 32000 ms\n"<br>+ output += "12. TxResp SIP/2.0 / 102 BYE - 200 OK\n"<br>+ elif command == "sip show history 2ec048aa4ed1239664f6408f0c5044c5@127.0.0.2:5060":<br>+ output = "* SIP Call\n"<br>+ output += "1. NewChan Channel SIP/ast1-00000002 - from 2ec048aa4ed1239664f6408f0c5044\n"<br>+ output += "2. TxReqRel INVITE / 102 INVITE - INVITE\n"<br>+ output += "3. Rx SIP/2.0 / 102 INVITE / 100 Trying\n"<br>+ output += "4. Rx SIP/2.0 / 102 INVITE / 200 OK\n"<br>+ output += "5. TxReq ACK / 102 ACK - ACK\n"<br>+ output += "6. Rx BYE / 102 BYE / sip:ast2@127.0.0.2:5060\n"<br>+ output += "7. RTCPaudio Quality:ssrc=28249381;themssrc=485141946;lp=0;rxjitter=0.000029\n"<br>+ output += "8. RTCPaudioJitter Quality:minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0\n"<br>+ output += "9. RTCPaudioLoss Quality:minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.00000\n"<br>+ output += "10. RTCPaudioRTT Quality:minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrt\n"<br>+ output += "11. SchedDestroy 32000 ms\n"<br>+ output += "12. TxResp SIP/2.0 / 102 BYE - 200 OK\n"<br>+ output += "13. Hangup Cause Normal Clearing\n"<br>+ return self.MockDefer(output)<br>+<br>+<br>+class AstMockObjectPostTestNoDialogsPass(AstMockOutput):<br>+ """Mock out CLI execution from Asterisk instance<br>+<br>+ This mock object makes it appear as if there were no dialogs, which is okay<br>+ """<br>+ def __init__(self):<br>+ """Constructor"""<br>+ self.host = "127.0.0.4"<br>+<br>+ def cli_exec(self, command):<br>+ """Mock CLI execution/response"""<br>+<br>+ output = ""<br>+ if command == "sip show objects":<br>+ output = "-= Peer objects: 4 static, 0 realtime, 0 autocreate =-\n\n"<br>+ output += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7001\ntype: peer\nobjflags: 0\nrefcount: 1\n\n"<br>+ output += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "-= Peer objects by IP =-\n\n"<br>+ output += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "-= Registry objects: 0 =-\n\n"<br>+ output += "-= Dialog objects:\n\n"<br>+<br>+ return self.MockDefer(output)<br>+<br>+<br>+class AstMockObjectPostTestPass(AstMockOutput):<br>+ """Mock out CLI execution from Asterisk instance<br>+<br>+ This mock object provides two dialogs with acceptable history<br>+ """<br>+ def __init__(self):<br>+ """Constructor"""<br>+ self.host = "127.0.0.3"<br>+<br>+ def cli_exec(self, command):<br>+ """Mock CLI execution/response"""<br>+<br>+ output = ""<br>+ if command == "sip show objects":<br>+ output = "-= Peer objects: 4 static, 0 realtime, 0 autocreate =-\n\n"<br>+ output += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7001\ntype: peer\nobjflags: 0\nrefcount: 1\n\n"<br>+ output += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "-= Peer objects by IP =-\n\n"<br>+ output += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "-= Registry objects: 0 =-\n\n"<br>+ output += "-= Dialog objects:\n\n"<br>+ output += "name: 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060\n"<br>+ output += "type: dialog\n"<br>+ output += "objflags: 0\n"<br>+ output += "refcount: 2\n\n"<br>+ output += "name: 2ec048aa4ed1239664f6408f0c5044c5@127.0.0.2:5060\n"<br>+ output += "type: dialog\n"<br>+ output += "objflags: 0\n"<br>+ output += "refcount: 2\n\n"<br>+ elif command == "sip show history 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060":<br>+ output = "* SIP Call\n"<br>+ output += "1. NewChan Channel SIP/ast1-00000002 - from 2ec048aa4ed1239664f6408f0c5044\n"<br>+ output += "2. TxReqRel INVITE / 102 INVITE - INVITE\n"<br>+ output += "3. Rx SIP/2.0 / 102 INVITE / 100 Trying\n"<br>+ output += "4. Rx SIP/2.0 / 102 INVITE / 200 OK\n"<br>+ output += "5. TxReq ACK / 102 ACK - ACK\n"<br>+ output += "6. Rx BYE / 102 BYE / sip:ast2@127.0.0.2:5060\n"<br>+ output += "7. RTCPaudio Quality:ssrc=28249381;themssrc=485141946;lp=0;rxjitter=0.000029\n"<br>+ output += "8. RTCPaudioJitter Quality:minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0\n"<br>+ output += "9. RTCPaudioLoss Quality:minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.00000\n"<br>+ output += "10. RTCPaudioRTT Quality:minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrt\n"<br>+ output += "11. SchedDestroy 32000 ms\n"<br>+ output += "12. TxResp SIP/2.0 / 102 BYE - 200 OK\n"<br>+ output += "13. Hangup Cause Normal Clearing\n"<br>+ elif command == "sip show history 2ec048aa4ed1239664f6408f0c5044c5@127.0.0.2:5060":<br>+ output = "* SIP Call\n"<br>+ output += "1. NewChan Channel SIP/ast1-00000002 - from 2ec048aa4ed1239664f6408f0c5044\n"<br>+ output += "2. TxReqRel INVITE / 102 INVITE - INVITE\n"<br>+ output += "3. Rx SIP/2.0 / 102 INVITE / 100 Trying\n"<br>+ output += "4. Rx SIP/2.0 / 102 INVITE / 200 OK\n"<br>+ output += "5. TxReq ACK / 102 ACK - ACK\n"<br>+ output += "6. Rx BYE / 102 BYE / sip:ast2@127.0.0.2:5060\n"<br>+ output += "7. RTCPaudio Quality:ssrc=28249381;themssrc=485141946;lp=0;rxjitter=0.000029\n"<br>+ output += "8. RTCPaudioJitter Quality:minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0\n"<br>+ output += "9. RTCPaudioLoss Quality:minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.00000\n"<br>+ output += "10. RTCPaudioRTT Quality:minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrt\n"<br>+ output += "11. SchedDestroy 32000 ms\n"<br>+ output += "12. TxResp SIP/2.0 / 102 BYE - 200 OK\n"<br>+ output += "13. Hangup Cause Normal Clearing\n"<br>+ return self.MockDefer(output)<br>+<br>+<br>+class AstMockObjectPreTestFail(AstMockOutput):<br>+ """Mock out CLI execution from Asterisk instance<br>+<br>+ This mock object provides history during a pre-test call, which is wrong<br>+ """<br>+ def __init__(self):<br>+ """Constructor"""<br>+ self.host = "127.0.0.2"<br>+<br>+ def cli_exec(self, command):<br>+ """Mock CLI execution/response"""<br>+<br>+ output = ""<br>+ if command == "sip show objects":<br>+ output = "-= Peer objects: 4 static, 0 realtime, 0 autocreate =-\n\n"<br>+ output += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7001\ntype: peer\nobjflags: 0\nrefcount: 1\n\n"<br>+ output += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "-= Peer objects by IP =-\n\n"<br>+ output += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "-= Registry objects: 0 =-\n\n"<br>+ output += "-= Dialog objects:\n\n"<br>+ output += "name: 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060\n"<br>+ output += "type: dialog\n"<br>+ output += "objflags: 0\n"<br>+ output += "refcount: 2\n\n"<br>+ elif command == "sip show history 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060":<br>+ output = "* SIP Call\n"<br>+ output += "1. NewChan Channel SIP/ast1-00000002 - from 2ec048aa4ed1239664f6408f0c5044\n"<br>+ output += "2. TxReqRel INVITE / 102 INVITE - INVITE\n"<br>+ output += "3. Rx SIP/2.0 / 102 INVITE / 100 Trying\n"<br>+ output += "4. Rx SIP/2.0 / 102 INVITE / 200 OK\n"<br>+ output += "5. TxReq ACK / 102 ACK - ACK\n"<br>+ output += "6. Rx BYE / 102 BYE / sip:ast2@127.0.0.2:5060\n"<br>+ output += "7. RTCPaudio Quality:ssrc=28249381;themssrc=485141946;lp=0;rxjitter=0.000029\n"<br>+ output += "8. RTCPaudioJitter Quality:minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0\n"<br>+ output += "9. RTCPaudioLoss Quality:minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.00000\n"<br>+ output += "10. RTCPaudioRTT Quality:minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrt\n"<br>+ output += "11. SchedDestroy 32000 ms\n"<br>+ output += "12. TxResp SIP/2.0 / 102 BYE - 200 OK\n"<br>+ output += "13. Hangup Cause Normal Clearing\n"<br>+ return self.MockDefer(output)<br>+<br>+<br>+class AstMockObjectPreTestPass(AstMockOutput):<br>+ """Mock out CLI execution from Asterisk instance<br>+<br>+ This mock object provides no history during a pre-test call, which is the<br>+ expected state<br>+ """<br>+ def cli_exec(self, command):<br>+ """Mock CLI execution/response"""<br>+<br>+ output = ""<br>+ if command == "sip show objects":<br>+ output = "-= Peer objects: 4 static, 0 realtime, 0 autocreate =-\n\n"<br>+ output += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7001\ntype: peer\nobjflags: 0\nrefcount: 1\n\n"<br>+ output += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "-= Peer objects by IP =-\n\n"<br>+ output += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>+ output += "-= Registry objects: 0 =-\n\n"<br>+ output += "-= Dialog objects:\n"<br>+ elif command == "sip show history":<br>+ output = "\n"<br>+ return self.MockDefer(output)<br>+<br>+<br>+@unittest.skip("sip_dialog_test_condition.py is broken")<br>+class SipDialogTestConditionUnitTest(unittest.TestCase):<br>+ """Unit tests for SipDialogTestCondition objects"""<br>+<br>+ def test_pre_test_pass(self):<br>+ """Verify that acceptable pre-test output passes"""<br>+ ast = AstMockObjectPreTestPass()<br>+ obj = SipDialogPreTestCondition(TestConfig())<br>+ obj.register_asterisk_instance(ast)<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Passed')<br>+<br>+ def test_pre_test_fail(self):<br>+ """Verify that unacceptable pre-test output fails"""<br>+ ast = AstMockObjectPreTestFail()<br>+ obj = SipDialogPreTestCondition(TestConfig())<br>+ obj.register_asterisk_instance(ast)<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Failed')<br>+<br>+ def test_pre_test_fail_multi_asterisk(self):<br>+ """Verify that pre-test output from multiple sources fails when one<br>+ of those sources is bad"""<br>+ ast1 = AstMockObjectPreTestFail()<br>+ ast2 = AstMockObjectPreTestPass()<br>+ obj = SipDialogPreTestCondition(TestConfig())<br>+ obj.register_asterisk_instance(ast1)<br>+ obj.register_asterisk_instance(ast2)<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Failed')<br>+<br>+ def test_post_test_pass(self):<br>+ """Verify nominal post-test output"""<br>+ ast = AstMockObjectPostTestPass()<br>+ obj = SipDialogPostTestCondition(TestConfigWithHistory())<br>+ obj.register_asterisk_instance(ast)<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Passed')<br>+<br>+ def test_post_test_no_dialog_pass(self):<br>+ """Verify nominal post-test output with no dialogs passes"""<br>+ ast = AstMockObjectPostTestNoDialogsPass()<br>+ obj = SipDialogPostTestCondition(TestConfig())<br>+ obj.register_asterisk_instance(ast)<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Passed')<br>+<br>+ def test_post_test_no_hangup_fail(self):<br>+ """Verify no hangup detection is caught and results in a failure"""<br>+ ast = AstMockObjectPostTestNoHangupFail()<br>+ obj = SipDialogPostTestCondition(TestConfigWithHistory())<br>+ obj.register_asterisk_instance(ast)<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Failed')<br>+<br>+ def test_post_test_no_destruction_fail(self):<br>+ """Verify no destruction is caught and results in a failure"""<br>+ ast = AstMockObjectPostTestNoDestructionFail()<br>+ obj = SipDialogPostTestCondition(TestConfigWithHistory())<br>+ obj.register_asterisk_instance(ast)<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Failed')<br>+<br>+ def test_post_test_multi_asterisk_fail(self):<br>+ """Test multiple instances of Asterisk where a single failure causes<br>+ a failure in the overall result"""<br>+ ast1 = AstMockObjectPostTestNoHangupFail()<br>+ ast2 = AstMockObjectPostTestNoDestructionFail()<br>+ ast3 = AstMockObjectPostTestNoDialogsPass()<br>+ ast4 = AstMockObjectPostTestPass()<br>+ obj = SipDialogPostTestCondition(TestConfigWithHistory())<br>+ obj.register_asterisk_instance(ast1)<br>+ obj.register_asterisk_instance(ast2)<br>+ obj.register_asterisk_instance(ast3)<br>+ obj.register_asterisk_instance(ast4)<br>+ obj.evaluate()<br>+ self.assertEqual(obj.get_status(), 'Failed')<br>+<br>+<br>+if __name__ == "__main__":<br>+ main()<br>diff --git a/lib/python/asterisk/self_test/test_sippversion.py b/lib/python/asterisk/self_test/test_sippversion.py<br>new file mode 100755<br>index 0000000..8c3d933<br>--- /dev/null<br>+++ b/lib/python/asterisk/self_test/test_sippversion.py<br>@@ -0,0 +1,221 @@<br>+#!/usr/bin/env python<br>+"""SIPp Version String Handling Tests<br>+<br>+Copyright (C) 2010, Digium, Inc.<br>+Paul Belanger <pabelanger@digium.com><br>+<br>+This program is free software, distributed under the terms of<br>+the GNU General Public License Version 2.<br>+"""<br>+<br>+from harness_shared import main<br>+import unittest<br>+from asterisk.sippversion import SIPpVersion<br>+<br>+<br>+class SIPpVersionTests(unittest.TestCase):<br>+ def test_version(self):<br>+ v = SIPpVersion("v3.2", None)<br>+ self.assertEqual(str(v), "v3.2")<br>+ self.assertEqual(v.concept, "v3")<br>+ self.assertEqual(v.major, "2")<br>+ self.assertEqual(v.minor, None)<br>+ self.assertFalse(v.tls)<br>+ self.assertFalse(v.pcap)<br>+<br>+ def test_version2(self):<br>+ v = SIPpVersion("v2.0.1", None)<br>+ self.assertEqual(str(v), "v2.0.1")<br>+ self.assertEqual(v.concept, "v2")<br>+ self.assertEqual(v.major, "0")<br>+ self.assertEqual(v.minor, "1")<br>+ self.assertFalse(v.tls)<br>+ self.assertFalse(v.pcap)<br>+<br>+ def test_version3(self):<br>+ v = SIPpVersion("v3.1", "TLS")<br>+ self.assertEqual(str(v), "v3.1-TLS")<br>+ self.assertEqual(v.concept, "v3")<br>+ self.assertEqual(v.major, "1")<br>+ self.assertEqual(v.minor, None)<br>+ self.assertTrue(v.tls)<br>+ self.assertFalse(v.pcap)<br>+<br>+ def test_version4(self):<br>+ v = SIPpVersion("v2.0.1", "TLS-PCAP")<br>+ self.assertEqual(str(v), "v2.0.1-TLS-PCAP")<br>+ self.assertEqual(v.concept, "v2")<br>+ self.assertEqual(v.major, "0")<br>+ self.assertEqual(v.minor, "1")<br>+ self.assertTrue(v.tls)<br>+ self.assertTrue(v.pcap)<br>+<br>+ def test_version5(self):<br>+ v = SIPpVersion("v3.2", "PCAP")<br>+ self.assertEqual(str(v), "v3.2-PCAP")<br>+ self.assertEqual(v.concept, "v3")<br>+ self.assertEqual(v.major, "2")<br>+ self.assertEqual(v.minor, None)<br>+ self.assertFalse(v.tls)<br>+ self.assertTrue(v.pcap)<br>+<br>+ def test_version6(self):<br>+ v = SIPpVersion(None, "PCAP")<br>+ self.assertEqual(str(v), "PCAP")<br>+ self.assertEqual(v.concept, None)<br>+ self.assertEqual(v.major, None)<br>+ self.assertEqual(v.minor, None)<br>+ self.assertFalse(v.tls)<br>+ self.assertTrue(v.pcap)<br>+<br>+ def test_version7(self):<br>+ v = SIPpVersion(None, "TLS")<br>+ self.assertEqual(str(v), "TLS")<br>+ self.assertEqual(v.concept, None)<br>+ self.assertEqual(v.major, None)<br>+ self.assertEqual(v.minor, None)<br>+ self.assertTrue(v.tls)<br>+ self.assertFalse(v.pcap)<br>+<br>+ def test_version8(self):<br>+ v = SIPpVersion(None, "TLS-PCAP")<br>+ self.assertEqual(str(v), "TLS-PCAP")<br>+ self.assertEqual(v.concept, None)<br>+ self.assertEqual(v.major, None)<br>+ self.assertEqual(v.minor, None)<br>+ self.assertTrue(v.tls)<br>+ self.assertTrue(v.pcap)<br>+<br>+ def test_cmp(self):<br>+ v1 = SIPpVersion("v3.2", None)<br>+ v2 = SIPpVersion("v3.1", None)<br>+ self.assertTrue(v1 > v2)<br>+<br>+ def test_cmp2(self):<br>+ v1 = SIPpVersion("v2.0.1", None)<br>+ v2 = SIPpVersion("v3.1", None)<br>+ self.assertTrue(v1 < v2)<br>+<br>+ def test_cmp3(self):<br>+ v1 = SIPpVersion("v3.1", None)<br>+ v2 = SIPpVersion("v3.1", None)<br>+ self.assertTrue(v1 == v2)<br>+<br>+ def test_cmp4(self):<br>+ v1 = SIPpVersion("v3.1", None)<br>+ v2 = SIPpVersion("v3.1", None)<br>+ self.assertFalse(v1 != v2)<br>+<br>+ def test_cmp5(self):<br>+ v1 = SIPpVersion("v3.1", "TLS")<br>+ v2 = SIPpVersion("v3.1", "TLS")<br>+ self.assertTrue(v1 == v2)<br>+<br>+ def test_cmp6(self):<br>+ v1 = SIPpVersion(None, "TLS")<br>+ v2 = SIPpVersion(None, "TLS")<br>+ self.assertTrue(v1 == v2)<br>+<br>+ def test_cmp7(self):<br>+ v1 = SIPpVersion("v2.0.1", None)<br>+ v2 = SIPpVersion("v2.0.1", None)<br>+ self.assertTrue(v1 == v2)<br>+<br>+ def test_cmp8(self):<br>+ v1 = SIPpVersion("v3.2", "TLS")<br>+ v2 = SIPpVersion("v3.2", "PCAP")<br>+ self.assertTrue(v1 != v2)<br>+<br>+ def test_cmp9(self):<br>+ v1 = SIPpVersion(None, "TLS")<br>+ v2 = SIPpVersion(None, "PCAP")<br>+ self.assertTrue(v1 != v2)<br>+<br>+ def test_cmp10(self):<br>+ v1 = SIPpVersion("v3.2", "TLS")<br>+ v2 = SIPpVersion("v3.2", "PCAP")<br>+ self.assertFalse(v1 == v2)<br>+<br>+ def test_cmp11(self):<br>+ v1 = SIPpVersion(None, "TLS")<br>+ v2 = SIPpVersion(None, "PCAP")<br>+ self.assertFalse(v1 == v2)<br>+<br>+ def test_cmp12(self):<br>+ v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>+ v2 = SIPpVersion("v3.2", "TLS")<br>+ self.assertTrue(v1 >= v2)<br>+<br>+ def test_cmp13(self):<br>+ v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>+ v2 = SIPpVersion(None, "TLS")<br>+ self.assertTrue(v1 >= v2)<br>+<br>+ def test_cmp14(self):<br>+ v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>+ v2 = SIPpVersion("v3.2", "PCAP")<br>+ self.assertTrue(v1 >= v2)<br>+<br>+ def test_cmp15(self):<br>+ v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>+ v2 = SIPpVersion(None, "PCAP")<br>+ self.assertTrue(v1 >= v2)<br>+<br>+ def test_cmp16(self):<br>+ v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>+ v2 = SIPpVersion("v3.2", "TLS")<br>+ self.assertTrue(v1 != v2)<br>+<br>+ def test_cmp17(self):<br>+ v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>+ v2 = SIPpVersion(None, "TLS")<br>+ self.assertTrue(v1 != v2)<br>+<br>+ def test_cmp18(self):<br>+ v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>+ v2 = SIPpVersion("v3.2", "TLS")<br>+ self.assertFalse(v1 == v2)<br>+<br>+ def test_cmp19(self):<br>+ v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>+ v2 = SIPpVersion(None, "TLS")<br>+ self.assertFalse(v1 == v2)<br>+<br>+ def test_cmp20(self):<br>+ v1 = SIPpVersion("v3.1", "PCAP")<br>+ v2 = SIPpVersion("v3.0", "TLS")<br>+ self.assertTrue(v1 > v2)<br>+<br>+ def test_cmp21(self):<br>+ v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>+ v2 = SIPpVersion("v2.0.1", "PCAP")<br>+ self.assertTrue(v1 >= v2)<br>+<br>+ def test_cmp22(self):<br>+ v1 = SIPpVersion("v3.1", "TLS")<br>+ v2 = SIPpVersion("v3.1", "PCAP")<br>+ self.assertFalse(v1 > v2)<br>+<br>+ def test_cmp23(self):<br>+ v1 = SIPpVersion("v3.1", "TLS")<br>+ v2 = SIPpVersion("v3.1", "PCAP")<br>+ self.assertFalse(v1 < v2)<br>+<br>+ def test_cmp24(self):<br>+ v1 = SIPpVersion("v3.2", "TLS")<br>+ v2 = SIPpVersion("v3.1", "TLS-PCAP")<br>+ self.assertTrue(v1 >= v2)<br>+<br>+ def test_cmp25(self):<br>+ v1 = SIPpVersion("v3.1", "TLS-PCAP")<br>+ v2 = SIPpVersion("v3.2", "PCAP")<br>+ self.assertTrue(v1 <= v2)<br>+<br>+ def test_cmp26(self):<br>+ v1 = SIPpVersion("v2.0.1", "TLS-PCAP")<br>+ v2 = SIPpVersion("v3.0", "TLS")<br>+ self.assertFalse(v1 >= v2)<br>+<br>+<br>+if __name__ == "__main__":<br>+ main()<br>diff --git a/lib/python/asterisk/self_test/test_utils_socket.py b/lib/python/asterisk/self_test/test_utils_socket.py<br>index 3a0c33d..34672c6 100755<br>--- a/lib/python/asterisk/self_test/test_utils_socket.py<br>+++ b/lib/python/asterisk/self_test/test_utils_socket.py<br>@@ -10,17 +10,10 @@<br> the GNU General Public License Version 2.<br> """<br> <br>-import logging<br>-import sys<br>+from harness_shared import main<br> import unittest<br>-<br> from socket import SOCK_STREAM, SOCK_DGRAM, AF_INET, AF_INET6<br>-<br>-sys.path.append('lib/python') # noqa<br> from asterisk.utils_socket import Ports, PortError, get_available_port, MIN_PORT<br>-<br>-<br>-LOGGER = logging.getLogger(__name__)<br> <br> <br> class PortTests(unittest.TestCase):<br>@@ -169,7 +162,4 @@<br> <br> if __name__ == "__main__":<br> """Run the unit tests"""<br>-<br>- logging.basicConfig(stream=sys.stdout, level=logging.DEBUG,<br>- format="%(module)s:%(lineno)d - %(message)s")<br>- unittest.main()<br>+ main()<br>diff --git a/lib/python/asterisk/sip_channel_test_condition.py b/lib/python/asterisk/sip_channel_test_condition.py<br>index 150d90f..0f265f0 100644<br>--- a/lib/python/asterisk/sip_channel_test_condition.py<br>+++ b/lib/python/asterisk/sip_channel_test_condition.py<br>@@ -10,7 +10,7 @@<br> """<br> <br> from twisted.internet import defer<br>-from test_conditions import TestCondition<br>+from .test_conditions import TestCondition<br> <br> <br> class SipChannelTestCondition(TestCondition):<br>diff --git a/lib/python/asterisk/sip_dialog_test_condition.py b/lib/python/asterisk/sip_dialog_test_condition.py<br>index 4c75710..619a388 100644<br>--- a/lib/python/asterisk/sip_dialog_test_condition.py<br>+++ b/lib/python/asterisk/sip_dialog_test_condition.py<br>@@ -10,9 +10,8 @@<br> <br> import logging<br> import logging.config<br>-import unittest<br> <br>-from test_conditions import TestCondition<br>+from .test_conditions import TestCondition<br> from twisted.internet import defer<br> <br> LOGGER = logging.getLogger(__name__)<br>@@ -227,422 +226,3 @@<br> self._counter = -1<br> __get_dialogs()<br> return self._finished_deferred<br>-<br>-<br>-class TestConfig(object):<br>- """Mock TestConfig object"""<br>-<br>- def __init__(self):<br>- """Constructor<br>-<br>- Values here don't matter much - we just need to have something"""<br>- self.type_name = ("asterisk.sip_dialog_test_condition." +<br>- "SipDialogPostTestCondition")<br>- self.pass_expected = True<br>- self.type = "Post"<br>- self.related_condition = ""<br>- self.config = {}<br>-<br>-<br>-class TestConfigWithHistory(TestConfig):<br>- """Mock TestConfig object with history requirements"""<br>-<br>- def __init__(self):<br>- """Constructor"""<br>- super(TestConfigWithHistory, self).__init__()<br>-<br>- self.config['history_requirements'] = []<br>- self.config['history_requirements'].append('Hangup')<br>- self.config['history_requirements'].append('NewChan')<br>-<br>-<br>-class AstMockObjectPostTestNoDestructionFail(object):<br>- """Mock out CLI execution from Asterisk instance<br>-<br>- This mock object makes it appear as if a dialog failed to be destroyed<br>- """<br>- def __init__(self):<br>- """Constructor"""<br>- self.host = "127.0.0.6"<br>-<br>- def cli_exec(self, command):<br>- """Mock CLI execution/response"""<br>-<br>- ret_string = ""<br>- if command == "sip show objects":<br>- ret_string = "-= Peer objects: 4 static, 0 realtime, 0 autocreate =-\n\n"<br>- ret_string += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7001\ntype: peer\nobjflags: 0\nrefcount: 1\n\n"<br>- ret_string += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "-= Peer objects by IP =-\n\n"<br>- ret_string += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "-= Registry objects: 0 =-\n\n"<br>- ret_string += "-= Dialog objects:\n\n"<br>- ret_string += "name: 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060\n"<br>- ret_string += "type: dialog\n"<br>- ret_string += "objflags: 0\n"<br>- ret_string += "refcount: 2\n\n"<br>- ret_string += "name: 2ec048aa4ed1239664f6408f0c5044c5@127.0.0.2:5060\n"<br>- ret_string += "type: dialog\n"<br>- ret_string += "objflags: 0\n"<br>- ret_string += "refcount: 2\n\n"<br>- elif command == "sip show history 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060":<br>- ret_string = "* SIP Call\n"<br>- ret_string += "1. NewChan Channel SIP/ast1-00000002 - from 2ec048aa4ed1239664f6408f0c5044\n"<br>- ret_string += "2. TxReqRel INVITE / 102 INVITE - INVITE\n"<br>- ret_string += "3. Rx SIP/2.0 / 102 INVITE / 100 Trying\n"<br>- ret_string += "4. Rx SIP/2.0 / 102 INVITE / 200 OK\n"<br>- ret_string += "5. TxReq ACK / 102 ACK - ACK\n"<br>- ret_string += "6. Rx BYE / 102 BYE / sip:ast2@127.0.0.2:5060\n"<br>- ret_string += "7. RTCPaudio Quality:ssrc=28249381;themssrc=485141946;lp=0;rxjitter=0.000029\n"<br>- ret_string += "8. RTCPaudioJitter Quality:minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0\n"<br>- ret_string += "9. RTCPaudioLoss Quality:minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.00000\n"<br>- ret_string += "10. RTCPaudioRTT Quality:minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrt\n"<br>- ret_string += "11. SchedDestroy 32000 ms\n"<br>- ret_string += "12. TxResp SIP/2.0 / 102 BYE - 200 OK\n"<br>- ret_string += "13. Hangup Cause Normal Clearing\n"<br>- elif command == "sip show history 2ec048aa4ed1239664f6408f0c5044c5@127.0.0.2:5060":<br>- ret_string = "* SIP Call\n"<br>- ret_string += "1. NewChan Channel SIP/ast1-00000002 - from 2ec048aa4ed1239664f6408f0c5044\n"<br>- ret_string += "2. TxReqRel INVITE / 102 INVITE - INVITE\n"<br>- ret_string += "3. Rx SIP/2.0 / 102 INVITE / 100 Trying\n"<br>- ret_string += "4. Rx SIP/2.0 / 102 INVITE / 200 OK\n"<br>- ret_string += "5. TxReq ACK / 102 ACK - ACK\n"<br>- ret_string += "6. Rx BYE / 102 BYE / sip:ast2@127.0.0.2:5060\n"<br>- ret_string += "7. RTCPaudio Quality:ssrc=28249381;themssrc=485141946;lp=0;rxjitter=0.000029\n"<br>- ret_string += "8. RTCPaudioJitter Quality:minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0\n"<br>- ret_string += "9. RTCPaudioLoss Quality:minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.00000\n"<br>- ret_string += "10. RTCPaudioRTT Quality:minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrt\n"<br>- ret_string += "11. TxResp SIP/2.0 / 102 BYE - 200 OK\n"<br>- ret_string += "12. Hangup Cause Normal Clearing\n"<br>- return ret_string<br>-<br>-<br>-class AstMockObjectPostTestNoHangupFail(object):<br>- """Mock out CLI execution from Asterisk instance<br>-<br>- This mock object makes it appear as if a channel failed to hangup<br>- """<br>-<br>- def __init__(self):<br>- """Constructor"""<br>- self.host = "127.0.0.5"<br>-<br>- def cli_exec(self, command):<br>- """Mock CLI execution/response"""<br>-<br>- ret_string = ""<br>- if command == "sip show objects":<br>- ret_string = "-= Peer objects: 4 static, 0 realtime, 0 autocreate =-\n\n"<br>- ret_string += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7001\ntype: peer\nobjflags: 0\nrefcount: 1\n\n"<br>- ret_string += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "-= Peer objects by IP =-\n\n"<br>- ret_string += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "-= Registry objects: 0 =-\n\n"<br>- ret_string += "-= Dialog objects:\n\n"<br>- ret_string += "name: 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060\n"<br>- ret_string += "type: dialog\n"<br>- ret_string += "objflags: 0\n"<br>- ret_string += "refcount: 2\n\n"<br>- ret_string += "name: 2ec048aa4ed1239664f6408f0c5044c5@127.0.0.2:5060\n"<br>- ret_string += "type: dialog\n"<br>- ret_string += "objflags: 0\n"<br>- ret_string += "refcount: 2\n\n"<br>- elif command == "sip show history 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060":<br>- ret_string = "* SIP Call\n"<br>- ret_string += "1. NewChan Channel SIP/ast1-00000002 - from 2ec048aa4ed1239664f6408f0c5044\n"<br>- ret_string += "2. TxReqRel INVITE / 102 INVITE - INVITE\n"<br>- ret_string += "3. Rx SIP/2.0 / 102 INVITE / 100 Trying\n"<br>- ret_string += "4. Rx SIP/2.0 / 102 INVITE / 200 OK\n"<br>- ret_string += "5. TxReq ACK / 102 ACK - ACK\n"<br>- ret_string += "6. Rx BYE / 102 BYE / sip:ast2@127.0.0.2:5060\n"<br>- ret_string += "7. RTCPaudio Quality:ssrc=28249381;themssrc=485141946;lp=0;rxjitter=0.000029\n"<br>- ret_string += "8. RTCPaudioJitter Quality:minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0\n"<br>- ret_string += "9. RTCPaudioLoss Quality:minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.00000\n"<br>- ret_string += "10. RTCPaudioRTT Quality:minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrt\n"<br>- ret_string += "11. SchedDestroy 32000 ms\n"<br>- ret_string += "12. TxResp SIP/2.0 / 102 BYE - 200 OK\n"<br>- elif command == "sip show history 2ec048aa4ed1239664f6408f0c5044c5@127.0.0.2:5060":<br>- ret_string = "* SIP Call\n"<br>- ret_string += "1. NewChan Channel SIP/ast1-00000002 - from 2ec048aa4ed1239664f6408f0c5044\n"<br>- ret_string += "2. TxReqRel INVITE / 102 INVITE - INVITE\n"<br>- ret_string += "3. Rx SIP/2.0 / 102 INVITE / 100 Trying\n"<br>- ret_string += "4. Rx SIP/2.0 / 102 INVITE / 200 OK\n"<br>- ret_string += "5. TxReq ACK / 102 ACK - ACK\n"<br>- ret_string += "6. Rx BYE / 102 BYE / sip:ast2@127.0.0.2:5060\n"<br>- ret_string += "7. RTCPaudio Quality:ssrc=28249381;themssrc=485141946;lp=0;rxjitter=0.000029\n"<br>- ret_string += "8. RTCPaudioJitter Quality:minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0\n"<br>- ret_string += "9. RTCPaudioLoss Quality:minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.00000\n"<br>- ret_string += "10. RTCPaudioRTT Quality:minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrt\n"<br>- ret_string += "11. SchedDestroy 32000 ms\n"<br>- ret_string += "12. TxResp SIP/2.0 / 102 BYE - 200 OK\n"<br>- ret_string += "13. Hangup Cause Normal Clearing\n"<br>- return ret_string<br>-<br>-<br>-class AstMockObjectPostTestNoDialogsPass(object):<br>- """Mock out CLI execution from Asterisk instance<br>-<br>- This mock object makes it appear as if there were no dialogs, which is okay<br>- """<br>- def __init__(self):<br>- """Constructor"""<br>- self.host = "127.0.0.4"<br>-<br>- def cli_exec(self, command):<br>- """Mock CLI execution/response"""<br>-<br>- ret_string = ""<br>- if command == "sip show objects":<br>- ret_string = "-= Peer objects: 4 static, 0 realtime, 0 autocreate =-\n\n"<br>- ret_string += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7001\ntype: peer\nobjflags: 0\nrefcount: 1\n\n"<br>- ret_string += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "-= Peer objects by IP =-\n\n"<br>- ret_string += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "-= Registry objects: 0 =-\n\n"<br>- ret_string += "-= Dialog objects:\n\n"<br>-<br>- return ret_string<br>-<br>-<br>-class AstMockObjectPostTestPass(object):<br>- """Mock out CLI execution from Asterisk instance<br>-<br>- This mock object provides two dialogs with acceptable history<br>- """<br>- def __init__(self):<br>- """Constructor"""<br>- self.host = "127.0.0.3"<br>-<br>- def cli_exec(self, command):<br>- """Mock CLI execution/response"""<br>-<br>- ret_string = ""<br>- if command == "sip show objects":<br>- ret_string = "-= Peer objects: 4 static, 0 realtime, 0 autocreate =-\n\n"<br>- ret_string += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7001\ntype: peer\nobjflags: 0\nrefcount: 1\n\n"<br>- ret_string += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "-= Peer objects by IP =-\n\n"<br>- ret_string += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "-= Registry objects: 0 =-\n\n"<br>- ret_string += "-= Dialog objects:\n\n"<br>- ret_string += "name: 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060\n"<br>- ret_string += "type: dialog\n"<br>- ret_string += "objflags: 0\n"<br>- ret_string += "refcount: 2\n\n"<br>- ret_string += "name: 2ec048aa4ed1239664f6408f0c5044c5@127.0.0.2:5060\n"<br>- ret_string += "type: dialog\n"<br>- ret_string += "objflags: 0\n"<br>- ret_string += "refcount: 2\n\n"<br>- elif command == "sip show history 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060":<br>- ret_string = "* SIP Call\n"<br>- ret_string += "1. NewChan Channel SIP/ast1-00000002 - from 2ec048aa4ed1239664f6408f0c5044\n"<br>- ret_string += "2. TxReqRel INVITE / 102 INVITE - INVITE\n"<br>- ret_string += "3. Rx SIP/2.0 / 102 INVITE / 100 Trying\n"<br>- ret_string += "4. Rx SIP/2.0 / 102 INVITE / 200 OK\n"<br>- ret_string += "5. TxReq ACK / 102 ACK - ACK\n"<br>- ret_string += "6. Rx BYE / 102 BYE / sip:ast2@127.0.0.2:5060\n"<br>- ret_string += "7. RTCPaudio Quality:ssrc=28249381;themssrc=485141946;lp=0;rxjitter=0.000029\n"<br>- ret_string += "8. RTCPaudioJitter Quality:minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0\n"<br>- ret_string += "9. RTCPaudioLoss Quality:minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.00000\n"<br>- ret_string += "10. RTCPaudioRTT Quality:minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrt\n"<br>- ret_string += "11. SchedDestroy 32000 ms\n"<br>- ret_string += "12. TxResp SIP/2.0 / 102 BYE - 200 OK\n"<br>- ret_string += "13. Hangup Cause Normal Clearing\n"<br>- elif command == "sip show history 2ec048aa4ed1239664f6408f0c5044c5@127.0.0.2:5060":<br>- ret_string = "* SIP Call\n"<br>- ret_string += "1. NewChan Channel SIP/ast1-00000002 - from 2ec048aa4ed1239664f6408f0c5044\n"<br>- ret_string += "2. TxReqRel INVITE / 102 INVITE - INVITE\n"<br>- ret_string += "3. Rx SIP/2.0 / 102 INVITE / 100 Trying\n"<br>- ret_string += "4. Rx SIP/2.0 / 102 INVITE / 200 OK\n"<br>- ret_string += "5. TxReq ACK / 102 ACK - ACK\n"<br>- ret_string += "6. Rx BYE / 102 BYE / sip:ast2@127.0.0.2:5060\n"<br>- ret_string += "7. RTCPaudio Quality:ssrc=28249381;themssrc=485141946;lp=0;rxjitter=0.000029\n"<br>- ret_string += "8. RTCPaudioJitter Quality:minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0\n"<br>- ret_string += "9. RTCPaudioLoss Quality:minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.00000\n"<br>- ret_string += "10. RTCPaudioRTT Quality:minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrt\n"<br>- ret_string += "11. SchedDestroy 32000 ms\n"<br>- ret_string += "12. TxResp SIP/2.0 / 102 BYE - 200 OK\n"<br>- ret_string += "13. Hangup Cause Normal Clearing\n"<br>- return ret_string<br>-<br>-<br>-class AstMockObjectPreTestFail(object):<br>- """Mock out CLI execution from Asterisk instance<br>-<br>- This mock object provides history during a pre-test call, which is wrong<br>- """<br>- def __init__(self):<br>- """Constructor"""<br>- self.host = "127.0.0.2"<br>-<br>- def cli_exec(self, command):<br>- """Mock CLI execution/response"""<br>-<br>- ret_string = ""<br>- if command == "sip show objects":<br>- ret_string = "-= Peer objects: 4 static, 0 realtime, 0 autocreate =-\n\n"<br>- ret_string += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7001\ntype: peer\nobjflags: 0\nrefcount: 1\n\n"<br>- ret_string += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "-= Peer objects by IP =-\n\n"<br>- ret_string += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "-= Registry objects: 0 =-\n\n"<br>- ret_string += "-= Dialog objects:\n\n"<br>- ret_string += "name: 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060\n"<br>- ret_string += "type: dialog\n"<br>- ret_string += "objflags: 0\n"<br>- ret_string += "refcount: 2\n\n"<br>- elif command == "sip show history 2ec048aa4ed1239664f6408f0c5044c4@127.0.0.2:5060":<br>- ret_string = "* SIP Call\n"<br>- ret_string += "1. NewChan Channel SIP/ast1-00000002 - from 2ec048aa4ed1239664f6408f0c5044\n"<br>- ret_string += "2. TxReqRel INVITE / 102 INVITE - INVITE\n"<br>- ret_string += "3. Rx SIP/2.0 / 102 INVITE / 100 Trying\n"<br>- ret_string += "4. Rx SIP/2.0 / 102 INVITE / 200 OK\n"<br>- ret_string += "5. TxReq ACK / 102 ACK - ACK\n"<br>- ret_string += "6. Rx BYE / 102 BYE / sip:ast2@127.0.0.2:5060\n"<br>- ret_string += "7. RTCPaudio Quality:ssrc=28249381;themssrc=485141946;lp=0;rxjitter=0.000029\n"<br>- ret_string += "8. RTCPaudioJitter Quality:minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0\n"<br>- ret_string += "9. RTCPaudioLoss Quality:minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.00000\n"<br>- ret_string += "10. RTCPaudioRTT Quality:minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrt\n"<br>- ret_string += "11. SchedDestroy 32000 ms\n"<br>- ret_string += "12. TxResp SIP/2.0 / 102 BYE - 200 OK\n"<br>- ret_string += "13. Hangup Cause Normal Clearing\n"<br>- return ret_string<br>-<br>-<br>-class AstMockObjectPreTestPass(object):<br>- """Mock out CLI execution from Asterisk instance<br>-<br>- This mock object provides no history during a pre-test call, which is the<br>- expected state<br>- """<br>- def __init__(self):<br>- """Constructor"""<br>- self.host = "127.0.0.1"<br>-<br>- def cli_exec(self, command):<br>- """Mock CLI execution/response"""<br>-<br>- ret_string = ""<br>- if command == "sip show objects":<br>- ret_string = "-= Peer objects: 4 static, 0 realtime, 0 autocreate =-\n\n"<br>- ret_string += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7001\ntype: peer\nobjflags: 0\nrefcount: 1\n\n"<br>- ret_string += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "-= Peer objects by IP =-\n\n"<br>- ret_string += "name: zoiper_01\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: audio\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "name: 7002\ntype: peer\nobjflags: 0\nrefcount: 3\n\n"<br>- ret_string += "-= Registry objects: 0 =-\n\n"<br>- ret_string += "-= Dialog objects:\n"<br>- elif command == "sip show history":<br>- return "\n"<br>- return ret_string<br>-<br>-<br>-class SipDialogTestConditionUnitTest(unittest.TestCase):<br>- """Unit tests for SipDialogTestCondition objects"""<br>-<br>- def test_pre_test_pass(self):<br>- """Verify that acceptable pre-test output passes"""<br>- ast = AstMockObjectPreTestPass()<br>- obj = SipDialogPreTestCondition(TestConfig())<br>- obj.register_asterisk_instance(ast)<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Passed')<br>-<br>- def test_pre_test_fail(self):<br>- """Verify that unacceptable pre-test output fails"""<br>- ast = AstMockObjectPreTestFail()<br>- obj = SipDialogPreTestCondition(TestConfig())<br>- obj.register_asterisk_instance(ast)<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Failed')<br>-<br>- def test_pre_test_fail_multi_asterisk(self):<br>- """Verify that pre-test output from multiple sources fails when one<br>- of those sources is bad"""<br>- ast1 = AstMockObjectPreTestFail()<br>- ast2 = AstMockObjectPreTestPass()<br>- obj = SipDialogPreTestCondition(TestConfig())<br>- obj.register_asterisk_instance(ast1)<br>- obj.register_asterisk_instance(ast2)<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Failed')<br>-<br>- def test_post_test_pass(self):<br>- """Verify nominal post-test output"""<br>- ast = AstMockObjectPostTestPass()<br>- obj = SipDialogPostTestCondition(TestConfigWithHistory())<br>- obj.register_asterisk_instance(ast)<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Passed')<br>-<br>- def test_post_test_no_dialog_pass(self):<br>- """Verify nominal post-test output with no dialogs passes"""<br>- ast = AstMockObjectPostTestNoDialogsPass()<br>- obj = SipDialogPostTestCondition(TestConfig())<br>- obj.register_asterisk_instance(ast)<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Passed')<br>-<br>- def test_post_test_no_hangup_fail(self):<br>- """Verify no hangup detection is caught and results in a failure"""<br>- ast = AstMockObjectPostTestNoHangupFail()<br>- obj = SipDialogPostTestCondition(TestConfigWithHistory())<br>- obj.register_asterisk_instance(ast)<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Failed')<br>-<br>- def test_post_test_no_destruction_fail(self):<br>- """Verify no destruction is caught and results in a failure"""<br>- ast = AstMockObjectPostTestNoDestructionFail()<br>- obj = SipDialogPostTestCondition(TestConfigWithHistory())<br>- obj.register_asterisk_instance(ast)<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Failed')<br>-<br>- def test_post_test_multi_asterisk_fail(self):<br>- """Test multiple instances of Asterisk where a single failure causes<br>- a failure in the overall result"""<br>- ast1 = AstMockObjectPostTestNoHangupFail()<br>- ast2 = AstMockObjectPostTestNoDestructionFail()<br>- ast3 = AstMockObjectPostTestNoDialogsPass()<br>- ast4 = AstMockObjectPostTestPass()<br>- obj = SipDialogPostTestCondition(TestConfigWithHistory())<br>- obj.register_asterisk_instance(ast1)<br>- obj.register_asterisk_instance(ast2)<br>- obj.register_asterisk_instance(ast3)<br>- obj.register_asterisk_instance(ast4)<br>- obj.evaluate()<br>- self.assertEqual(obj.get_status(), 'Failed')<br>-<br>-<br>-def main():<br>- """Execute the unit tests"""<br>- logging.basicConfig(level=logging.DEBUG)<br>- unittest.main()<br>-<br>-<br>-if __name__ == "__main__":<br>- main()<br>diff --git a/lib/python/asterisk/sipp.py b/lib/python/asterisk/sipp.py<br>index b84965e..540a544 100644<br>--- a/lib/python/asterisk/sipp.py<br>+++ b/lib/python/asterisk/sipp.py<br>@@ -10,12 +10,12 @@<br> """<br> <br> import logging<br>-import test_suite_utils<br>+from . import test_suite_utils<br> <br> from abc import ABCMeta, abstractmethod<br> from twisted.internet import reactor, defer, protocol, error<br>-from test_case import TestCase<br>-from utils_socket import get_available_port<br>+from .test_case import TestCase<br>+from .utils_socket import get_available_port<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>@@ -495,7 +495,7 @@<br> def outReceived(self, data):<br> """Override of ProcessProtocol.outReceived"""<br> LOGGER.debug("Received from SIPp scenario %s: %s" % (self._name, data))<br>- self.output += data<br>+ self.output += data.decode('utf-8', 'ignore')<br> <br> def connectionMade(self):<br> """Override of ProcessProtocol.connectionMade"""<br>diff --git a/lib/python/asterisk/sippversion.py b/lib/python/asterisk/sippversion.py<br>index b1110fc..f942e9c 100644<br>--- a/lib/python/asterisk/sippversion.py<br>+++ b/lib/python/asterisk/sippversion.py<br>@@ -1,4 +1,3 @@<br>-#!/usr/bin/env python<br> """SIPp Version String Handling<br> <br> Copyright (C) 2010, Digium, Inc.<br>@@ -9,11 +8,7 @@<br> """<br> <br> import subprocess<br>-import sys<br>-import unittest<br>-sys.path.append("lib/python")<br>-<br>-import test_suite_utils<br>+from . import test_suite_utils<br> <br> <br> class SIPpVersion:<br>@@ -48,8 +43,9 @@<br> except OSError:<br> return<br> for line in sipp_process.stdout:<br>- if line.strip().startswith('SIPp '):<br>- sipp = line.strip()[5:]<br>+ line = line.decode('utf-8').strip()<br>+ if line.startswith('SIPp '):<br>+ sipp = line[5:]<br> sipp = sipp.split(',', 1)<br> sipp = sipp[0].split('-', 1)<br> version = sipp[0]<br>@@ -88,7 +84,7 @@<br> <br> def __cmp__(self, other):<br> """Compare two SIPpVersion instances against each other"""<br>- return cmp(int(self), int(other))<br>+ return (int(self) > int(other)) - (int(self) < int(other))<br> <br> def __ne__(self, other):<br> """Determine if this SIPpVersion instance is not equal to another"""<br>@@ -105,6 +101,14 @@<br> if ((res == 0) and (self.tls == other.tls and self.pcap == other.pcap)):<br> return True<br> return False<br>+<br>+ def __le__(self, other):<br>+ """Determine if this SIPpVersion instance is less than or equal to another"""<br>+ return int(self) <= int(other)<br>+<br>+ def __lt__(self, other):<br>+ """Determine if this SIPpVersion instance is less than another"""<br>+ return int(self) < int(other)<br> <br> def __parse_version(self, version):<br> """Parse the version string returned from SIPp"""<br>@@ -124,215 +128,3 @@<br> self.tls = True<br> if value.find("PCAP") > -1:<br> self.pcap = True<br>-<br>-<br>-class SIPpVersionTests(unittest.TestCase):<br>- def test_version(self):<br>- v = SIPpVersion("v3.2", None)<br>- self.assertEqual(str(v), "v3.2")<br>- self.assertEqual(v.concept, "v3")<br>- self.assertEqual(v.major, "2")<br>- self.assertEqual(v.minor, None)<br>- self.assertFalse(v.tls)<br>- self.assertFalse(v.pcap)<br>-<br>- def test_version2(self):<br>- v = SIPpVersion("v2.0.1", None)<br>- self.assertEqual(str(v), "v2.0.1")<br>- self.assertEqual(v.concept, "v2")<br>- self.assertEqual(v.major, "0")<br>- self.assertEqual(v.minor, "1")<br>- self.assertFalse(v.tls)<br>- self.assertFalse(v.pcap)<br>-<br>- def test_version3(self):<br>- v = SIPpVersion("v3.1", "TLS")<br>- self.assertEqual(str(v), "v3.1-TLS")<br>- self.assertEqual(v.concept, "v3")<br>- self.assertEqual(v.major, "1")<br>- self.assertEqual(v.minor, None)<br>- self.assertTrue(v.tls)<br>- self.assertFalse(v.pcap)<br>-<br>- def test_version4(self):<br>- v = SIPpVersion("v2.0.1", "TLS-PCAP")<br>- self.assertEqual(str(v), "v2.0.1-TLS-PCAP")<br>- self.assertEqual(v.concept, "v2")<br>- self.assertEqual(v.major, "0")<br>- self.assertEqual(v.minor, "1")<br>- self.assertTrue(v.tls)<br>- self.assertTrue(v.pcap)<br>-<br>- def test_version5(self):<br>- v = SIPpVersion("v3.2", "PCAP")<br>- self.assertEqual(str(v), "v3.2-PCAP")<br>- self.assertEqual(v.concept, "v3")<br>- self.assertEqual(v.major, "2")<br>- self.assertEqual(v.minor, None)<br>- self.assertFalse(v.tls)<br>- self.assertTrue(v.pcap)<br>-<br>- def test_version6(self):<br>- v = SIPpVersion(None, "PCAP")<br>- self.assertEqual(str(v), "PCAP")<br>- self.assertEqual(v.concept, None)<br>- self.assertEqual(v.major, None)<br>- self.assertEqual(v.minor, None)<br>- self.assertFalse(v.tls)<br>- self.assertTrue(v.pcap)<br>-<br>- def test_version7(self):<br>- v = SIPpVersion(None, "TLS")<br>- self.assertEqual(str(v), "TLS")<br>- self.assertEqual(v.concept, None)<br>- self.assertEqual(v.major, None)<br>- self.assertEqual(v.minor, None)<br>- self.assertTrue(v.tls)<br>- self.assertFalse(v.pcap)<br>-<br>- def test_version8(self):<br>- v = SIPpVersion(None, "TLS-PCAP")<br>- self.assertEqual(str(v), "TLS-PCAP")<br>- self.assertEqual(v.concept, None)<br>- self.assertEqual(v.major, None)<br>- self.assertEqual(v.minor, None)<br>- self.assertTrue(v.tls)<br>- self.assertTrue(v.pcap)<br>-<br>- def test_cmp(self):<br>- v1 = SIPpVersion("v3.2", None)<br>- v2 = SIPpVersion("v3.1", None)<br>- self.assertTrue(v1 > v2)<br>-<br>- def test_cmp2(self):<br>- v1 = SIPpVersion("v2.0.1", None)<br>- v2 = SIPpVersion("v3.1", None)<br>- self.assertTrue(v1 < v2)<br>-<br>- def test_cmp3(self):<br>- v1 = SIPpVersion("v3.1", None)<br>- v2 = SIPpVersion("v3.1", None)<br>- self.assertTrue(v1 == v2)<br>-<br>- def test_cmp4(self):<br>- v1 = SIPpVersion("v3.1", None)<br>- v2 = SIPpVersion("v3.1", None)<br>- self.assertFalse(v1 != v2)<br>-<br>- def test_cmp5(self):<br>- v1 = SIPpVersion("v3.1", "TLS")<br>- v2 = SIPpVersion("v3.1", "TLS")<br>- self.assertTrue(v1 == v2)<br>-<br>- def test_cmp6(self):<br>- v1 = SIPpVersion(None, "TLS")<br>- v2 = SIPpVersion(None, "TLS")<br>- self.assertTrue(v1 == v2)<br>-<br>- def test_cmp7(self):<br>- v1 = SIPpVersion("v2.0.1", None)<br>- v2 = SIPpVersion("v2.0.1", None)<br>- self.assertTrue(v1 == v2)<br>-<br>- def test_cmp8(self):<br>- v1 = SIPpVersion("v3.2", "TLS")<br>- v2 = SIPpVersion("v3.2", "PCAP")<br>- self.assertTrue(v1 != v2)<br>-<br>- def test_cmp9(self):<br>- v1 = SIPpVersion(None, "TLS")<br>- v2 = SIPpVersion(None, "PCAP")<br>- self.assertTrue(v1 != v2)<br>-<br>- def test_cmp10(self):<br>- v1 = SIPpVersion("v3.2", "TLS")<br>- v2 = SIPpVersion("v3.2", "PCAP")<br>- self.assertFalse(v1 == v2)<br>-<br>- def test_cmp11(self):<br>- v1 = SIPpVersion(None, "TLS")<br>- v2 = SIPpVersion(None, "PCAP")<br>- self.assertFalse(v1 == v2)<br>-<br>- def test_cmp12(self):<br>- v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>- v2 = SIPpVersion("v3.2", "TLS")<br>- self.assertTrue(v1 >= v2)<br>-<br>- def test_cmp13(self):<br>- v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>- v2 = SIPpVersion(None, "TLS")<br>- self.assertTrue(v1 >= v2)<br>-<br>- def test_cmp14(self):<br>- v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>- v2 = SIPpVersion("v3.2", "PCAP")<br>- self.assertTrue(v1 >= v2)<br>-<br>- def test_cmp15(self):<br>- v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>- v2 = SIPpVersion(None, "PCAP")<br>- self.assertTrue(v1 >= v2)<br>-<br>- def test_cmp16(self):<br>- v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>- v2 = SIPpVersion("v3.2", "TLS")<br>- self.assertTrue(v1 != v2)<br>-<br>- def test_cmp17(self):<br>- v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>- v2 = SIPpVersion(None, "TLS")<br>- self.assertTrue(v1 != v2)<br>-<br>- def test_cmp18(self):<br>- v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>- v2 = SIPpVersion("v3.2", "TLS")<br>- self.assertFalse(v1 == v2)<br>-<br>- def test_cmp19(self):<br>- v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>- v2 = SIPpVersion(None, "TLS")<br>- self.assertFalse(v1 == v2)<br>-<br>- def test_cmp20(self):<br>- v1 = SIPpVersion("v3.1", "PCAP")<br>- v2 = SIPpVersion("v3.0", "TLS")<br>- self.assertTrue(v1 > v2)<br>-<br>- def test_cmp21(self):<br>- v1 = SIPpVersion("v3.2", "TLS-PCAP")<br>- v2 = SIPpVersion("v2.0.1", "PCAP")<br>- self.assertTrue(v1 >= v2)<br>-<br>- def test_cmp22(self):<br>- v1 = SIPpVersion("v3.1", "TLS")<br>- v2 = SIPpVersion("v3.1", "PCAP")<br>- self.assertFalse(v1 > v2)<br>-<br>- def test_cmp23(self):<br>- v1 = SIPpVersion("v3.1", "TLS")<br>- v2 = SIPpVersion("v3.1", "PCAP")<br>- self.assertFalse(v1 < v2)<br>-<br>- def test_cmp24(self):<br>- v1 = SIPpVersion("v3.2", "TLS")<br>- v2 = SIPpVersion("v3.1", "TLS-PCAP")<br>- self.assertTrue(v1 >= v2)<br>-<br>- def test_cmp25(self):<br>- v1 = SIPpVersion("v3.1", "TLS-PCAP")<br>- v2 = SIPpVersion("v3.2", "PCAP")<br>- self.assertTrue(v1 <= v2)<br>-<br>- def test_cmp26(self):<br>- v1 = SIPpVersion("v2.0.1", "TLS-PCAP")<br>- v2 = SIPpVersion("v3.0", "TLS")<br>- self.assertFalse(v1 >= v2)<br>-<br>-<br>-def main():<br>- unittest.main()<br>-<br>-<br>-if __name__ == "__main__":<br>- main()<br>diff --git a/lib/python/asterisk/syncami.py b/lib/python/asterisk/syncami.py<br>index 031ae99..5482400 100644<br>--- a/lib/python/asterisk/syncami.py<br>+++ b/lib/python/asterisk/syncami.py<br>@@ -8,7 +8,13 @@<br> the GNU General Public License Version 2.<br> """<br> <br>-from urllib import urlencode<br>+try:<br>+ # python 2 import<br>+ from urllib import urlencode<br>+except:<br>+ # python 3 import<br>+ from urllib.parse import urlencode<br>+<br> from email.parser import HeaderParser<br> try:<br> from httplib import *<br>@@ -87,7 +93,7 @@<br> if res.status != 200:<br> raise InvalidAMIResponse(res)<br> self.cookie = res.getheader('set-cookie', None)<br>- data = res.read()<br>+ data = res.read().decode('utf-8')<br> parser = HeaderParser()<br> <br> return parser.parsestr(data)<br>diff --git a/lib/python/asterisk/test_case.py b/lib/python/asterisk/test_case.py<br>index 80321f7..7bf6d16 100644<br>--- a/lib/python/asterisk/test_case.py<br>+++ b/lib/python/asterisk/test_case.py<br>@@ -19,9 +19,9 @@<br> from twisted.python import log<br> from starpy import manager, fastagi<br> <br>-from asterisk import Asterisk<br>-from test_config import TestConfig<br>-from test_conditions import TestConditionController<br>+from .asterisk import Asterisk<br>+from .test_config import TestConfig<br>+from .test_conditions import TestConditionController<br> <br> <br> try:<br>@@ -45,12 +45,12 @@<br> except:<br> msg = ("WARNING: failed to preserve existing loggers - some "<br> "logging statements may be missing")<br>- print msg<br>+ print(msg)<br> logging.config.fileConfig(config_file)<br> else:<br> msg = ("WARNING: no logging.conf file found; using default "<br> "configuration")<br>- print msg<br>+ print(msg)<br> logging.basicConfig(level=logging.DEBUG)<br> <br> root_logger = logging.getLogger()<br>@@ -102,7 +102,7 @@<br> # for the rasterisk CLI connection. As a quick fix, we hash the path<br> # using md5, to make it unique enough.<br> self.realbase = self.test_name.replace("tests/", "", 1)<br>- self.base = md5(self.realbase).hexdigest()<br>+ self.base = md5(self.realbase.encode()).hexdigest()<br> # We provide a symlink to it from a named path.<br> named_dir = os.path.join(Asterisk.test_suite_root, self.realbase)<br> try:<br>diff --git a/lib/python/asterisk/test_conditions.py b/lib/python/asterisk/test_conditions.py<br>index dbf36a7..7053465 100644<br>--- a/lib/python/asterisk/test_conditions.py<br>+++ b/lib/python/asterisk/test_conditions.py<br>@@ -19,7 +19,7 @@<br> import logging<br> import logging.config<br> <br>-from buildoptions import AsteriskBuildOptions<br>+from .buildoptions import AsteriskBuildOptions<br> from twisted.internet import defer<br> <br> LOGGER = logging.getLogger(__name__)<br>diff --git a/lib/python/asterisk/test_config.py b/lib/python/asterisk/test_config.py<br>index 8fdb884..6d2318d 100644<br>--- a/lib/python/asterisk/test_config.py<br>+++ b/lib/python/asterisk/test_config.py<br>@@ -18,12 +18,13 @@<br> <br> sys.path.append("lib/python")<br> <br>-import test_suite_utils<br>+from . import test_suite_utils<br>+from .test_runner import load_and_parse_module<br> <br>-from asterisk import Asterisk<br>-from buildoptions import AsteriskBuildOptions<br>-from sippversion import SIPpVersion<br>-from opensslversion import OpenSSLVersion<br>+from .asterisk import Asterisk<br>+from .buildoptions import AsteriskBuildOptions<br>+from .sippversion import SIPpVersion<br>+from .opensslversion import OpenSSLVersion<br> <br> <br> class TestConditionConfig(object):<br>@@ -70,14 +71,9 @@<br> <br> def make_condition(self):<br> """Build and return the condition object defined by this config"""<br>- parts = self.class_type_name.split('.')<br>- module = '.'.join(parts[:-1])<br>- if module != '':<br>- mod = __import__(module)<br>- for comp in parts[1:]:<br>- mod = getattr(mod, comp)<br>- obj = mod(self)<br>- return obj<br>+ mod = load_and_parse_module(self.class_type_name)<br>+ if mod is not None:<br>+ return mod(self)<br> return None<br> <br> <br>@@ -147,7 +143,7 @@<br> self.met = getattr(self, dir_method)()<br> found = True<br> if not found:<br>- print "Unknown custom dependency - '%s'" % self.name<br>+ print("Unknown custom dependency - '%s'" % self.name)<br> elif "asterisk" in dep:<br> if self.ast:<br> self.name = dep["asterisk"]<br>@@ -167,9 +163,9 @@<br> from test_case import PCAP_AVAILABLE<br> self.met = PCAP_AVAILABLE<br> else:<br>- print "Unknown dependency type specified:"<br>+ print("Unknown dependency type specified:")<br> for key in dep.keys():<br>- print key<br>+ print(key)<br> <br> def depend_remote(self):<br> """Check to see if we run against a remote instance of Asterisk"""<br>@@ -256,13 +252,13 @@<br> if self.asterisk_build_options:<br> return (self.asterisk_build_options.check_option(name))<br> else:<br>- print "Unable to evaluate build options: no build options found"<br>+ print("Unable to evaluate build options: no build options found")<br> return False<br> <br> def _find_asterisk_module(self, name):<br> """Determine if an Asterisk module exists"""<br> if not Dependency.ast:<br>- print "Unable to evaluate Asterisk modules: Asterisk not found"<br>+ print("Unable to evaluate Asterisk modules: Asterisk not found")<br> return False<br> <br> if Dependency.ast.original_astmoddir == "":<br>@@ -333,8 +329,8 @@<br> if self.config is not None and 'exclude-tests' in self.config:<br> self.excluded_tests = self.config['exclude-tests']<br> else:<br>- print ("WARNING - test configuration [%s] not found in "<br>- "config file" % self.test_configuration)<br>+ print("WARNING - test configuration [%s] not found in "<br>+ "config file" % self.test_configuration)<br> <br> def _process_testinfo(self):<br> """Process the test information block"""<br>@@ -381,8 +377,8 @@<br> self.config = yaml.load(config_file)<br> <br> if not self.config:<br>- print "ERROR: Failed to load configuration for test '%s'" % \<br>- self.test_name<br>+ print("ERROR: Failed to load configuration for test '%s'" %<br>+ self.test_name)<br> return<br> <br> self._process_global_settings()<br>@@ -408,8 +404,8 @@<br> matches = [cond_def for cond_def in self.condition_definitions<br> if cond_def['name'] == conf['name']]<br> if len(matches) != 1:<br>- print ("Unknown or too many matches for condition: " +<br>- conf['name'])<br>+ print("Unknown or too many matches for condition: " +<br>+ conf['name'])<br> else:<br> pre_cond = TestConditionConfig(conf, matches[0], "Pre")<br> post_cond = TestConditionConfig(conf, matches[0], "Post")<br>diff --git a/lib/python/asterisk/test_runner.py b/lib/python/asterisk/test_runner.py<br>old mode 100755<br>new mode 100644<br>index 644d117..d278e02<br>--- a/lib/python/asterisk/test_runner.py<br>+++ b/lib/python/asterisk/test_runner.py<br>@@ -1,4 +1,3 @@<br>-#!/usr/bin/env python<br> """Module that spawns and manages running a test<br> <br> This module provides an entry point, loading, and teardown of test<br>@@ -22,8 +21,6 @@<br> <br> LOGGER = logging.getLogger('test_runner')<br> logging.basicConfig()<br>-<br>-sys.path.append('lib/python')<br> <br> <br> class TestModuleFinder(object):<br>@@ -144,9 +141,18 @@<br> module_name = ".".join(parts[:-1])<br> <br> if not len(module_name):<br>- LOGGER.error("No module specified: %s" % module_name)<br>+ LOGGER.error("No module specified: %s" % typename)<br> return None<br> <br>+ if os.path.exists('lib/python/asterisk/%s.py' % module_name):<br>+ # This is convoluted but required. lib/python/asterisk packages<br>+ # must be loaded using absolute package names and 'asterisk' must<br>+ # be included in the list of parts. We cannot simply prepend<br>+ # type_name from the start because this blocks load of modules<br>+ # that are local to the test (add-test-to-search-path: 'True').<br>+ module_name = 'asterisk.' + module_name<br>+ parts = ['asterisk'] + parts<br>+<br> module = __import__(module_name)<br> for comp in parts[1:]:<br> module = getattr(module, comp)<br>diff --git a/lib/python/asterisk/test_suite_utils.py b/lib/python/asterisk/test_suite_utils.py<br>index d8ef541..84f54f5 100644<br>--- a/lib/python/asterisk/test_suite_utils.py<br>+++ b/lib/python/asterisk/test_suite_utils.py<br>@@ -1,4 +1,3 @@<br>-#! /usr/bin/env python<br> """Asterisk testsuite utils<br> <br> This module provides access to Asterisk testsuite utility<br>@@ -14,15 +13,19 @@<br> import os<br> import logging<br> import re<br>+import sys<br> <br> from os import close<br> from os import remove<br> from shutil import move<br> from tempfile import mkstemp<br>-from config import ConfigFile<br>+from .config import ConfigFile<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>+<br>+if sys.version_info[0] == 3:<br>+ unicode = str<br> <br> def which(program):<br> """Find the executable for a specified program<br>@@ -100,7 +103,7 @@<br> elif isinstance(pattern, dict):<br> # Dict should match for every field in the pattern.<br> # extra fields in the message are fine.<br>- for key, value in pattern.iteritems():<br>+ for key, value in pattern.items():<br> to_check = message.get(key)<br> if to_check is None or not all_match(value, to_check):<br> return False<br>diff --git a/lib/python/asterisk/thread_test_condition.py b/lib/python/asterisk/thread_test_condition.py<br>index 595e3ce..c12321f 100644<br>--- a/lib/python/asterisk/thread_test_condition.py<br>+++ b/lib/python/asterisk/thread_test_condition.py<br>@@ -9,7 +9,7 @@<br> """<br> <br> import logging<br>-from test_conditions import TestCondition<br>+from .test_conditions import TestCondition<br> from twisted.internet import defer<br> <br> LOGGER = logging.getLogger(__name__)<br>diff --git a/lib/python/asterisk/voicemail.py b/lib/python/asterisk/voicemail.py<br>index 283650b..3c4c7d5 100644<br>--- a/lib/python/asterisk/voicemail.py<br>+++ b/lib/python/asterisk/voicemail.py<br>@@ -20,9 +20,9 @@<br> import time<br> import random<br> <br>-from config import ConfigFile<br>-from test_case import TestCase<br>-from test_state import TestState, TestStateController, FailureTestState<br>+from .config import ConfigFile<br>+from .test_case import TestCase<br>+from .test_state import TestState, TestStateController, FailureTestState<br> <br> sys.path.append("lib/python")<br> <br>diff --git a/lib/python/rlmi.py b/lib/python/rlmi.py<br>index 5e662a0..2abf19e 100644<br>--- a/lib/python/rlmi.py<br>+++ b/lib/python/rlmi.py<br>@@ -343,7 +343,7 @@<br> return None<br> @classmethod<br> def gds_reverse_node_mapping(cls, mapping):<br>- return dict(((v, k) for k, v in mapping.iteritems()))<br>+ return dict(((v, k) for k, v in mapping.items()))<br> <br> <br> #<br>diff --git a/lib/python/sip_message.py b/lib/python/sip_message.py<br>index 85cd9fd..087c760 100644<br>--- a/lib/python/sip_message.py<br>+++ b/lib/python/sip_message.py<br>@@ -118,7 +118,7 @@<br> def main():<br> msg = """INVITE sip:123@example.com SIP/2.0\r\nContact : \tTerry Wilson\r\n <terry@example.com>\r\nCall-ID:\r\n Whatever\r\nContact: New Contact\r\n\r\nData!!!!!"""<br> sipmsg = SIPMessage(msg)<br>- print sipmsg<br>+ print(sipmsg)<br> if sipmsg.get_header('CoNtact') is None:<br> return -1<br> if len(sipmsg.get_header_all('contact')) != 2:<br>diff --git a/run-local b/run-local<br>index 026a063..326ac50 100755<br>--- a/run-local<br>+++ b/run-local<br>@@ -75,7 +75,12 @@<br> LIBDIR=`dirname $HERE/astroot/usr/lib*/libasteriskssl.so`<br> export LD_LIBRARY_PATH="${LIBDIR}${LD_LIBRARY_PATH}"<br> set +e<br>- ./runtests.py "$@"<br>+ if test -n "$PYTHON"; then<br>+ # Use specific interpreter<br>+ $PYTHON ./runtests.py "$@"<br>+ else<br>+ ./runtests.py "$@"<br>+ fi<br> status=$?<br> rm "$AST_TEST_ROOT"<br> set -e<br>diff --git a/runtests.py b/runtests.py<br>index 1351a3c..eac88a1 100755<br>--- a/runtests.py<br>+++ b/runtests.py<br>@@ -111,7 +111,7 @@<br> <br> def stdout_print(self, msg):<br> self.stdout += msg + "\n"<br>- print msg<br>+ print(msg)<br> <br> def run(self):<br> self.passed = False<br>@@ -124,13 +124,14 @@<br> ]<br> <br> if not os.path.exists(cmd[0]):<br>- cmd = ["./lib/python/asterisk/test_runner.py",<br>+ cmd = [sys.executable,<br>+ "-m", "asterisk.test_runner",<br> "%s" % self.test_name]<br> if os.path.exists(cmd[0]) and os.access(cmd[0], os.X_OK):<br> if self.options.pcap:<br> os.environ['PCAP'] = "yes"<br> <br>- self.stdout_print("Running %s ..." % cmd)<br>+ self.stdout_print("Running %s ..." % self.test_name)<br> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,<br> stderr=subprocess.STDOUT)<br> self.pid = p.pid<br>@@ -139,6 +140,7 @@<br> poll.register(p.stdout, select.POLLIN)<br> <br> timedout = False<br>+ has_unicode_error = False<br> try:<br> while (not abandon_test):<br> try:<br>@@ -148,20 +150,24 @@<br> except select.error as v:<br> if v[0] != errno.EINTR:<br> raise<br>- l = p.stdout.readline()<br>+ l = p.stdout.readline().decode('ascii', 'ignore').strip()<br> if not l:<br> break<br> self.stdout_print(l)<br>+ except UnicodeEncodeError:<br>+ self.stdout_print('Unicode error reading output from test!')<br>+ has_unicode_error = True<br>+ pass<br> except IOError:<br> pass<br> p.wait()<br> <br> # Sanitize p.returncode so it's always a boolean.<br>- did_pass = (p.returncode == 0 and not abandon_test)<br>+ did_pass = (p.returncode == 0 and not abandon_test and not has_unicode_error)<br> if did_pass and not self.test_config.expect_pass:<br> self.stdout_print("Test passed but was expected to fail.")<br> if not did_pass and not self.test_config.expect_pass:<br>- print "Test failed as expected."<br>+ print("Test failed as expected.")<br> <br> self.passed = (did_pass == self.test_config.expect_pass)<br> if abandon_test:<br>@@ -190,8 +196,8 @@<br> shutil.rmtree(absolute_dir)<br> os.remove(symlink_dir)<br> except:<br>- print "Unable to clean up directory for" \<br>- "test %s (non-fatal)" % self.test_name<br>+ print("Unable to clean up directory for"<br>+ "test %s (non-fatal)" % self.test_name)<br> <br> self.__parse_run_output(self.stdout)<br> if timedout:<br>@@ -202,13 +208,13 @@<br> status = 'passed'<br> else:<br> status = 'failed'<br>- pass_str = 'Test %s %s\n' % (cmd, status)<br>- print pass_str<br>+ pass_str = 'Test %s %s\n' % (self.test_name, status)<br>+ print(pass_str)<br> if self.options.syslog:<br> syslog.syslog(pass_str)<br> <br> else:<br>- print "FAILED TO EXECUTE %s, it must exist and be executable" % cmd<br>+ print("FAILED TO EXECUTE %s, it must exist and be executable" % cmd)<br> self.time = time.time() - start_time<br> <br> def _check_for_core(self):<br>@@ -237,7 +243,7 @@<br> debug_level = email_config.get('debug', 0)<br> <br> if not sender or len(recipients) == 0:<br>- print "--email-on-crash requires sender and 1+ recipients"<br>+ print("--email-on-crash requires sender and 1+ recipients")<br> return<br> <br> with open(dest_file_name, 'r') as bt_file:<br>@@ -255,12 +261,12 @@<br> send_email(smtp_server, sender, recipients, message,<br> debug=debug_level)<br> except Exception as exception:<br>- print "Failed to send email\nError: {0}".format(exception)<br>+ print("Failed to send email\nError: {0}".format(exception))<br> <br> def _archive_core_dumps(self, core_dumps):<br> for core in core_dumps:<br> if not os.path.exists(core):<br>- print "Unable to find core dump file %s, skipping" % core<br>+ print("Unable to find core dump file %s, skipping" % core)<br> continue<br> random_num = random.randint(0, 16000)<br> dest_dir = "./logs/%s" % self.test_relpath<br>@@ -275,36 +281,36 @@<br> "-ex", "thread apply all bt",<br> "--batch",<br> "-c", core]<br>- print "Running %s" % (" ".join(gdb_cmd),)<br>+ print("Running %s" % (" ".join(gdb_cmd),))<br> try:<br> res = subprocess.call(gdb_cmd, stdout=dest_file, stderr=subprocess.STDOUT)<br> if res != 0:<br>- print "error analyzing core dump; gdb exited with %d" % res<br>+ print("error analyzing core dump; gdb exited with %d" % res)<br> # Copy the backtrace over to the logs<br>- print "Archived backtrace: {0}".format(dest_file_name)<br>+ print("Archived backtrace: {0}".format(dest_file_name))<br> <br> if self.options.email_on_crash:<br> self._email_crash_report(dest_file_name)<br> <br>- except OSError, ose:<br>- print "OSError ([%d]: %s) occurred while executing %r" % \<br>- (ose.errno, ose.strerror, gdb_cmd)<br>+ except OSError as ose:<br>+ print("OSError ([%d]: %s) occurred while executing %r" %<br>+ (ose.errno, ose.strerror, gdb_cmd))<br> except:<br>- print "Unknown exception occurred while executing %r" % (gdb_cmd,)<br>+ print("Unknown exception occurred while executing %r" % (gdb_cmd,))<br> finally:<br> dest_file.close()<br> if self.options.keep_core:<br> try:<br> dst_core = os.path.join(dest_dir, "core_{0}".format(random_num))<br> shutil.copy(core, dst_core)<br>- print "Archived core file: {0}".format(dst_core)<br>+ print("Archived core file: {0}".format(dst_core))<br> except Exception as e:<br>- print "Error occurred while copying core: {0}".format(e)<br>+ print("Error occurred while copying core: {0}".format(e))<br> try:<br> os.unlink(core)<br>- except OSError, e:<br>- print "Error removing core file: %s: " \<br>- "Beware of the stale core file in CWD!" % (e,)<br>+ except OSError as e:<br>+ print("Error removing core file: %s: "<br>+ "Beware of the stale core file in CWD!" % (e,))<br> <br> def _find_run_dirs(self):<br> test_run_dir = os.path.join(Asterisk.test_suite_root,<br>@@ -387,7 +393,7 @@<br> res = subprocess.call(refcounter,<br> stdout=dest_file,<br> stderr=subprocess.STDOUT)<br>- except Exception, e:<br>+ except Exception as e:<br> self.stdout_print("Exception occurred while processing REF_DEBUG")<br> finally:<br> dest_file.close()<br>@@ -415,10 +421,10 @@<br> srcfile = os.path.join(src_dir, filename)<br> if os.path.exists(srcfile):<br> hardlink_or_copy(srcfile, os.path.join(dest_dir, filename))<br>- except Exception, e:<br>- print "Exception occurred while archiving file '%s' to %s: %s" % (<br>+ except Exception as e:<br>+ print("Exception occurred while archiving file '%s' to %s: %s" % (<br> srcfile, dest_dir, e<br>- )<br>+ ))<br> <br> def _archive_logs(self):<br> (run_num, run_dir, archive_dir) = self._find_run_dirs()<br>@@ -519,35 +525,35 @@<br> tags.sort(key=str.lower)<br> maxwidth = max(len(t) for t in tags)<br> <br>- print "Available test tags:"<br>+ print("Available test tags:")<br> tags = chunks(tags, 3)<br> for tag in tags:<br>- print "\t%-*s %-*s %-*s" % (<br>+ print("\t%-*s %-*s %-*s" % (<br> maxwidth, tag[0],<br> maxwidth, len(tag) > 1 and tag[1] or '',<br>- maxwidth, len(tag) > 2 and tag[2] or '')<br>+ maxwidth, len(tag) > 2 and tag[2] or ''))<br> <br> def list_tests(self):<br>- print "Configured tests:"<br>+ print("Configured tests:")<br> i = 1<br> for t in self.tests:<br>- print "%.3d) %s" % (i, t.test_config.test_name)<br>- print " --> Summary: %s" % t.test_config.summary<br>+ print("%.3d) %s" % (i, t.test_config.test_name))<br>+ print(" --> Summary: %s" % t.test_config.summary)<br> if t.test_config.skip is not None:<br>- print " --> Skip: %s" % t.test_config.skip<br>+ print(" --> Skip: %s" % t.test_config.skip)<br> if t.test_config.features:<br>- print " --> Features:"<br>+ print(" --> Features:")<br> for feature_name in t.test_config.features:<br>- print " --> %s: -- Met: %s" % \<br>- (feature_name, str(t.test_config.feature_check[feature_name]))<br>+ print(" --> %s: -- Met: %s" %<br>+ (feature_name, str(t.test_config.feature_check[feature_name])))<br> if t.test_config.tags:<br>- print " --> Tags: %s" % str(t.test_config.tags)<br>+ print(" --> Tags: %s" % str(t.test_config.tags))<br> for d in t.test_config.deps:<br> if d.version:<br>- print " --> Dependency: %s" % (d.name)<br>- print " --> Version: %s -- Met: %s" % (d.version, str(d.met))<br>+ print(" --> Dependency: %s" % (d.name))<br>+ print(" --> Version: %s -- Met: %s" % (d.version, str(d.met)))<br> else:<br>- print " --> Dependency: %s -- Met: %s" % (d.name, str(d.met))<br>+ print(" --> Dependency: %s -- Met: %s" % (d.name, str(d.met)))<br> <br> i += 1<br> <br>@@ -571,7 +577,7 @@<br> else:<br> deps += ("%s" % d.name)<br> <br>- print "%04d %s %s%s" % (i, flag, t.test_config.test_name, deps)<br>+ print("%04d %s %s%s" % (i, flag, t.test_config.test_name, deps))<br> i += 1<br> <br> def run(self):<br>@@ -587,8 +593,8 @@<br> if excluded in t.test_name:<br> continue<br> i += 1<br>- print "Tests to run: %d * %d time(s) = %d Maximum test inactivity time: %d sec." % \<br>- (i, self.options.number, i * self.options.number, (self.options.timeout / 1000))<br>+ print("Tests to run: %d * %d time(s) = %d Maximum test inactivity time: %d sec." %<br>+ (i, self.options.number, i * self.options.number, (self.options.timeout / 1000)))<br> <br> for t in self.tests:<br> if abandon_test_suite:<br>@@ -596,18 +602,18 @@<br> <br> if t.can_run is False:<br> if t.test_config.skip is not None:<br>- print "--> %s ... skipped '%s'" % (t.test_name, t.test_config.skip)<br>+ print("--> %s ... skipped '%s'" % (t.test_name, t.test_config.skip))<br> t.skipped_reason = t.test_config.skip<br> self.total_skipped += 1<br> continue<br>- print "--> Cannot run test '%s'" % t.test_name<br>+ print("--> Cannot run test '%s'" % t.test_name)<br> for f in t.test_config.features:<br>- print "--- --> Version Feature: %s - %s" % (<br>- f, str(t.test_config.feature_check[f]))<br>- print "--- --> Tags: %s" % (t.test_config.tags)<br>+ print("--- --> Version Feature: %s - %s" % (<br>+ f, str(t.test_config.feature_check[f])))<br>+ print("--- --> Tags: %s" % (t.test_config.tags))<br> for d in t.test_config.deps:<br>- print "--- --> Dependency: %s - %s" % (d.name, str(d.met))<br>- print<br>+ print("--- --> Dependency: %s - %s" % (d.name, str(d.met)))<br>+ print("")<br> self.total_skipped += 1<br> t.skipped_reason = "Failed dependency"<br> continue<br>@@ -615,14 +621,14 @@<br> exclude = False<br> for excluded in self.global_config.excluded_tests:<br> if excluded in t.test_name:<br>- print "--- ---> Excluded test: %s" % excluded<br>+ print("--- ---> Excluded test: %s" % excluded)<br> exclude = True<br> if exclude:<br> self.total_skipped += 1<br> continue<br> <br> running_str = "--> Running test '%s' ..." % t.test_name<br>- print running_str<br>+ print(running_str)<br> if self.options.syslog:<br> syslog.syslog(running_str)<br> <br>@@ -630,16 +636,16 @@<br> t.passed = True<br> else:<br> # Establish Preconditions<br>- print "Making sure Asterisk isn't running ..."<br>+ print("Making sure Asterisk isn't running ...")<br> if os.system("if pidof asterisk >/dev/null; then "<br> "killall -9 asterisk >/dev/null 2>&1; "<br> "sleep 1; ! pidof asterisk >/dev/null; fi"):<br>- print "Could not kill asterisk."<br>- print "Making sure SIPp isn't running..."<br>+ print("Could not kill asterisk.")<br>+ print("Making sure SIPp isn't running...")<br> if os.system("if pidof sipp >/dev/null; then "<br> "killall -9 sipp >/dev/null 2>&1; "<br> "sleep 1; ! pidof sipp >/dev/null; fi"):<br>- print "Could not kill sipp."<br>+ print("Could not kill sipp.")<br> # XXX TODO Hard coded path, gross.<br> os.system("rm -f /var/run/asterisk/asterisk.ctl")<br> os.system("rm -f /var/run/asterisk/asterisk.pid")<br>@@ -668,12 +674,12 @@<br> (0x86, 0x9f),<br> ]<br> <br>- char_list = []<br>+ tbl = {}<br> for r in bad_chars:<br> # we do +1 here to include the last item<br> for i in range(r[0], r[1] + 1):<br>- char_list.append(chr(i))<br>- return data.translate(None, ''.join(char_list))<br>+ tbl[chr(i)] = None<br>+ return data.translate(tbl)<br> <br> def write_results_xml(self, doc, root):<br> <br>@@ -728,10 +734,10 @@<br> except IOError:<br> # Ignore errors for the optional tests/custom folder.<br> if path != "tests/custom/tests.yaml":<br>- print "Failed to open %s" % path<br>+ print("Failed to open %s" % path)<br> return None<br> except:<br>- print "Unexpected error: %s" % sys.exc_info()[0]<br>+ print("Unexpected error: %s" % sys.exc_info()[0])<br> return None<br> <br> config = yaml.load(f)<br>@@ -747,7 +753,7 @@<br> """<br> global abandon_test_suite<br> <br>- print "SIGUSR1 received; stopping test suite after current test..."<br>+ print("SIGUSR1 received; stopping test suite after current test...")<br> abandon_test_suite = True<br> <br> <br>@@ -760,7 +766,7 @@<br> global abandon_test<br> global abandon_test_suite<br> <br>- print "SIGTREM received; abandoning current test and stopping..."<br>+ print("SIGTREM received; abandoning current test and stopping...")<br> abandon_test = True<br> abandon_test_suite = True<br> <br>@@ -877,8 +883,8 @@<br> <br> if options.valgrind:<br> if not ET:<br>- print "python lxml module not loaded, text summaries " \<br>- "from valgrind will not be produced.\n"<br>+ print("python lxml module not loaded, text summaries "<br>+ "from valgrind will not be produced.\n")<br> os.environ["VALGRIND_ENABLE"] = "true"<br> <br> dom = xml.dom.getDOMImplementation()<br>@@ -894,7 +900,7 @@<br> <br> running_str = "Running tests for Asterisk (run {0} of {1})...\n".format(<br> iteration + 1, options.number)<br>- print running_str<br>+ print(running_str)<br> if options.syslog:<br> syslog.syslog(running_str)<br> <br>@@ -903,22 +909,22 @@<br> <br> # If exactly one test was requested, then skip the summary.<br> if len(test_suite.tests) != 1:<br>- print "\n=== TEST RESULTS ===\n"<br>- print "PATH: %s\n" % os.getenv("PATH")<br>+ print("\n=== TEST RESULTS ===\n")<br>+ print("PATH: %s\n" % os.getenv("PATH"))<br> for t in test_suite.tests:<br> sys.stdout.write("--> %s --- " % t.test_name)<br> if t.did_run is False:<br>- print "SKIPPED"<br>+ print("SKIPPED")<br> for d in t.test_config.deps:<br>- print " --> Dependency: %s -- Met: %s" % (d.name, str(d.met))<br>+ print(" --> Dependency: %s -- Met: %s" % (d.name, str(d.met)))<br> if options.tags:<br> for t in t.test_config.tags:<br>- print " --> Tag: %s -- Met: %s" % (t, str(t in options.tags))<br>+ print(" --> Tag: %s -- Met: %s" % (t, str(t in options.tags)))<br> continue<br> if t.passed is True:<br>- print "PASSED"<br>+ print("PASSED")<br> else:<br>- print "FAILED"<br>+ print("FAILED")<br> <br> iteration += 1<br> <br>@@ -929,11 +935,11 @@<br> with open(TEST_RESULTS, "w") as f:<br> doc.writexml(f, addindent=" ", newl="\n", encoding="utf-8")<br> except IOError:<br>- print "Failed to open test results output file: %s" % TEST_RESULTS<br>+ print("Failed to open test results output file: %s" % TEST_RESULTS)<br> except:<br>- print "Unexpected error: %s" % sys.exc_info()[0]<br>- print "\n"<br>- print doc.toprettyxml(" ", encoding="utf-8")<br>+ print("Unexpected error: %s" % sys.exc_info()[0])<br>+ print("\n")<br>+ print(doc.toprettyxml(" ", encoding="utf-8").decode('utf-8', 'ignore'))<br> <br> if options.syslog:<br> syslog.syslog("All tests concluded")<br>@@ -954,7 +960,7 @@<br> <br> try:<br> os.link(source, destination)<br>- except OSError, e:<br>+ except OSError as e:<br> # Different partitions can cause hard links to fail (error 18),<br> # if there's a different error, bail out immediately.<br> if e.args[0] != errno.EXDEV:<br>diff --git a/self_test b/self_test<br>index 1936014..045c090 100755<br>--- a/self_test<br>+++ b/self_test<br>@@ -28,17 +28,3 @@<br> run_test $i python2 $PYTHON2<br> [ "${i#test2}" = "${i}" ] && run_test $i python3 $PYTHON3<br> done<br>-<br>-# Temporary code for running unit tests that are not compatible with python3<br>-run_legacy_test() {<br>- # Arguments: test_name python_name python_bin<br>- if test -n "$3"; then<br>- echo " ==> Executing $1 ($2)"<br>- $3 lib/python/asterisk/${1}.py<br>- fi<br>-}<br>-<br>-for i in buildoptions channel_test_condition sippversion; do<br>- run_legacy_test $i python $PYTHON<br>- run_legacy_test $i python2 $PYTHON2<br>-done<br>diff --git a/tests/cdr/cdr-tests.py b/tests/cdr/cdr-tests.py<br>index a284673..9090045 100644<br>--- a/tests/cdr/cdr-tests.py<br>+++ b/tests/cdr/cdr-tests.py<br>@@ -13,8 +13,8 @@<br> import time<br> <br> sys.path.append("lib/python")<br>-from cdr import CDRModule<br>-from cdr import AsteriskCSVCDR<br>+from asterisk.cdr import CDRModule<br>+from asterisk.cdr import AsteriskCSVCDR<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>diff --git a/tests/cdr/sqlite3/cdr_sqlite3.py b/tests/cdr/sqlite3/cdr_sqlite3.py<br>index 1def05e..32ed786 100644<br>--- a/tests/cdr/sqlite3/cdr_sqlite3.py<br>+++ b/tests/cdr/sqlite3/cdr_sqlite3.py<br>@@ -14,7 +14,7 @@<br> import re<br> <br> sys.path.append("lib/python")<br>-from config import ConfigFile<br>+from asterisk.config import ConfigFile<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>diff --git a/tests/channels/SIP/tcpauthlimit/sipp_scenario.py b/tests/channels/SIP/tcpauthlimit/sipp_scenario.py<br>index 76a21aa..55a26f5 100644<br>--- a/tests/channels/SIP/tcpauthlimit/sipp_scenario.py<br>+++ b/tests/channels/SIP/tcpauthlimit/sipp_scenario.py<br>@@ -9,7 +9,7 @@<br> <br> import logging<br> <br>-from sipp import SIPpScenario<br>+from asterisk.sipp import SIPpScenario<br> from twisted.internet import defer<br> <br> LOGGER = logging.getLogger(__name__)<br>diff --git a/tests/channels/pjsip/registration/inbound/nominal/contact_acl/ipv4/scenario_generator.py b/tests/channels/pjsip/registration/inbound/nominal/contact_acl/ipv4/scenario_generator.py<br>index 2e2357a..4fcb67a 100755<br>--- a/tests/channels/pjsip/registration/inbound/nominal/contact_acl/ipv4/scenario_generator.py<br>+++ b/tests/channels/pjsip/registration/inbound/nominal/contact_acl/ipv4/scenario_generator.py<br>@@ -12,8 +12,8 @@<br> <br> sys.path.append("lib/python")<br> <br>-import test_suite_utils<br>-from sipp import ScenarioGenerator<br>+from asterisk import test_suite_utils<br>+from asterisk.sipp import ScenarioGenerator<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>diff --git a/tests/channels/pjsip/registration/inbound/nominal/contact_acl/ipv6/scenario_generator.py b/tests/channels/pjsip/registration/inbound/nominal/contact_acl/ipv6/scenario_generator.py<br>index 2a52c96..541ba62 100755<br>--- a/tests/channels/pjsip/registration/inbound/nominal/contact_acl/ipv6/scenario_generator.py<br>+++ b/tests/channels/pjsip/registration/inbound/nominal/contact_acl/ipv6/scenario_generator.py<br>@@ -12,8 +12,8 @@<br> <br> sys.path.append("lib/python")<br> <br>-import test_suite_utils<br>-from sipp import ScenarioGenerator<br>+from asterisk import test_suite_utils<br>+from asterisk.sipp import ScenarioGenerator<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>diff --git a/tests/channels/pjsip/subscriptions/presence/verify_bodies/presence.py b/tests/channels/pjsip/subscriptions/presence/verify_bodies/presence.py<br>index 143ea42..bbff8f8 100644<br>--- a/tests/channels/pjsip/subscriptions/presence/verify_bodies/presence.py<br>+++ b/tests/channels/pjsip/subscriptions/presence/verify_bodies/presence.py<br>@@ -15,7 +15,7 @@<br> <br> sys.path.append('lib/python')<br> <br>-from pcap import VOIPListener<br>+from asterisk.pcap import VOIPListener<br> from twisted.internet import reactor<br> <br> LOGGER = logging.getLogger(__name__)<br>diff --git a/tests/channels/pjsip/subscriptions/rls/rls_test.py b/tests/channels/pjsip/subscriptions/rls/rls_test.py<br>index 9c4051c..08d0567 100644<br>--- a/tests/channels/pjsip/subscriptions/rls/rls_test.py<br>+++ b/tests/channels/pjsip/subscriptions/rls/rls_test.py<br>@@ -13,7 +13,7 @@<br> sys.path.append("lib/python")<br> sys.path.append("tests/channels/pjsip/subscriptions/rls")<br> <br>-from pcap import VOIPProxy<br>+from asterisk.pcap import VOIPProxy<br> from rls_element import RLSPacket<br> from rls_validation import ValidationInfo<br> from twisted.internet import reactor<br>diff --git a/tests/channels/pjsip/transfers/attended_transfer/nominal/packet_sniffer.py b/tests/channels/pjsip/transfers/attended_transfer/nominal/packet_sniffer.py<br>index a96a661..b49f268 100755<br>--- a/tests/channels/pjsip/transfers/attended_transfer/nominal/packet_sniffer.py<br>+++ b/tests/channels/pjsip/transfers/attended_transfer/nominal/packet_sniffer.py<br>@@ -35,8 +35,8 @@<br> <br> sys.path.append('lib/python')<br> <br>-from phones import PjsuaPhoneController<br>-from pcap import VOIPListener<br>+from asterisk.phones import PjsuaPhoneController<br>+from asterisk.pcap import VOIPListener<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>diff --git a/tests/codecs/audio_analyzer.py b/tests/codecs/audio_analyzer.py<br>index 9903c6d..e656777 100644<br>--- a/tests/codecs/audio_analyzer.py<br>+++ b/tests/codecs/audio_analyzer.py<br>@@ -13,8 +13,8 @@<br> import logging<br> from twisted.internet import reactor<br> <br>-import ami<br>-import ari<br>+from asterisk import ami<br>+from asterisk import ari<br> import tonetest<br> <br> sys.path.append("lib/python")<br>diff --git a/tests/codecs/rtp_analyzer.py b/tests/codecs/rtp_analyzer.py<br>index e20cde3..74f161a 100644<br>--- a/tests/codecs/rtp_analyzer.py<br>+++ b/tests/codecs/rtp_analyzer.py<br>@@ -13,7 +13,7 @@<br> <br> sys.path.append("lib/python")<br> <br>-import pcap<br>+from asterisk import pcap<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>diff --git a/tests/hep/hep_capture_node.py b/tests/hep/hep_capture_node.py<br>index f663056..3e7feae 100644<br>--- a/tests/hep/hep_capture_node.py<br>+++ b/tests/hep/hep_capture_node.py<br>@@ -28,7 +28,7 @@<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>-from test_suite_utils import all_match<br>+from asterisk.test_suite_utils import all_match<br> <br> def enum(**enums):<br> """Make an enumeration out of the passed in values"""<br>diff --git a/tests/manager/config/ManagerConfigTest.py b/tests/manager/config/ManagerConfigTest.py<br>index b7dbd8a..fe2e65f 100644<br>--- a/tests/manager/config/ManagerConfigTest.py<br>+++ b/tests/manager/config/ManagerConfigTest.py<br>@@ -13,8 +13,8 @@<br> <br> sys.path.append("lib/python")<br> <br>-from test_case import TestCase<br>-from syncami import SyncAMI<br>+from asterisk.test_case import TestCase<br>+from asterisk.syncami import SyncAMI<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>diff --git a/tests/manager/device_state_changed/ami_device_state.py b/tests/manager/device_state_changed/ami_device_state.py<br>index a3ac5f3..96d8021 100644<br>--- a/tests/manager/device_state_changed/ami_device_state.py<br>+++ b/tests/manager/device_state_changed/ami_device_state.py<br>@@ -8,7 +8,7 @@<br> '''<br> <br> import logging<br>-from test_case import TestCase<br>+from asterisk.test_case import TestCase<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>diff --git a/tests/manager/device_state_list/ami_device_state_list.py b/tests/manager/device_state_list/ami_device_state_list.py<br>index 5abd104..105780e 100755<br>--- a/tests/manager/device_state_list/ami_device_state_list.py<br>+++ b/tests/manager/device_state_list/ami_device_state_list.py<br>@@ -9,7 +9,7 @@<br> """<br> <br> import logging<br>-from test_case import TestCase<br>+from asterisk.test_case import TestCase<br> from twisted.internet import defer<br> <br> LOGGER = logging.getLogger(__name__)<br>diff --git a/tests/manager/exten_state_list/ami_exten_state_list.py b/tests/manager/exten_state_list/ami_exten_state_list.py<br>index c9449f4..90bdc4f 100755<br>--- a/tests/manager/exten_state_list/ami_exten_state_list.py<br>+++ b/tests/manager/exten_state_list/ami_exten_state_list.py<br>@@ -9,7 +9,7 @@<br> """<br> <br> import logging<br>-from test_case import TestCase<br>+from asterisk.test_case import TestCase<br> from twisted.internet import defer<br> <br> LOGGER = logging.getLogger(__name__)<br>diff --git a/tests/manager/presence_state_changed/ami_presence_state.py b/tests/manager/presence_state_changed/ami_presence_state.py<br>index e6861fc..d8ac551 100644<br>--- a/tests/manager/presence_state_changed/ami_presence_state.py<br>+++ b/tests/manager/presence_state_changed/ami_presence_state.py<br>@@ -8,7 +8,7 @@<br> '''<br> <br> import logging<br>-from test_case import TestCase<br>+from asterisk.test_case import TestCase<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>diff --git a/tests/manager/presence_state_list/ami_presence_state_list.py b/tests/manager/presence_state_list/ami_presence_state_list.py<br>index 13c16c7..f67c386 100755<br>--- a/tests/manager/presence_state_list/ami_presence_state_list.py<br>+++ b/tests/manager/presence_state_list/ami_presence_state_list.py<br>@@ -9,7 +9,7 @@<br> """<br> <br> import logging<br>-from test_case import TestCase<br>+from asterisk.test_case import TestCase<br> from twisted.internet import defer<br> <br> LOGGER = logging.getLogger(__name__)<br>diff --git a/tests/pbx/manager_extensions/ami_extension_control.py b/tests/pbx/manager_extensions/ami_extension_control.py<br>index d4ac26c..01e53af 100755<br>--- a/tests/pbx/manager_extensions/ami_extension_control.py<br>+++ b/tests/pbx/manager_extensions/ami_extension_control.py<br>@@ -8,7 +8,7 @@<br> '''<br> <br> import logging<br>-from test_case import TestCase<br>+from asterisk.test_case import TestCase<br> from twisted.internet import defer<br> <br> LOGGER = logging.getLogger(__name__)<br>diff --git a/tests/rest_api/external_interaction/attended_transfer/attended_transfer.py b/tests/rest_api/external_interaction/attended_transfer/attended_transfer.py<br>index d03fbfe..6b7790c 100644<br>--- a/tests/rest_api/external_interaction/attended_transfer/attended_transfer.py<br>+++ b/tests/rest_api/external_interaction/attended_transfer/attended_transfer.py<br>@@ -9,7 +9,7 @@<br> import logging<br> from sys import path<br> <br>-from sipp import SIPpScenario<br>+from asterisk.sipp import SIPpScenario<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>diff --git a/tests/rest_api/external_interaction/blind_transfer/call_transfer.py b/tests/rest_api/external_interaction/blind_transfer/call_transfer.py<br>index 23f1a7b..ddef074 100755<br>--- a/tests/rest_api/external_interaction/blind_transfer/call_transfer.py<br>+++ b/tests/rest_api/external_interaction/blind_transfer/call_transfer.py<br>@@ -16,7 +16,7 @@<br> import pjsua as pj<br> from twisted.internet import reactor<br> <br>-import pjsua_mod<br>+from asterisk import pjsua_mod<br> <br> LOGGER = logging.getLogger(__name__)<br> THIS_FILE = os.path.basename(__file__)<br>diff --git a/tests/rest_api/message/message_modules.py b/tests/rest_api/message/message_modules.py<br>index 2e4cdd4..c2d8f2e 100644<br>--- a/tests/rest_api/message/message_modules.py<br>+++ b/tests/rest_api/message/message_modules.py<br>@@ -14,7 +14,7 @@<br> <br> from twisted.internet import defer<br> <br>-from sipp import SIPpScenario<br>+from asterisk.sipp import SIPpScenario<br> <br> LOGGER = logging.getLogger(__name__)<br> <br>diff --git a/usage.py b/usage.py<br>index 16dea94..9e7c33f 100755<br>--- a/usage.py<br>+++ b/usage.py<br>@@ -70,7 +70,7 @@<br> def occurances(self, **kwargs):<br> match = []<br> for test in self.tests:<br>- for key, value in kwargs.iteritems():<br>+ for key, value in kwargs.items():<br> if value in getattr(test, key):<br> match.append(test)<br> continue<br>@@ -78,14 +78,14 @@<br> return len(match)<br> <br> def results_for(self, key):<br>- print key.title() + ":"<br>+ print(key.title() + ":")<br> things = self.unique(key)<br> width = max(len(t) for t in things)<br> results = [(self.occurances(**{key: t}), t) for t in things]<br> results.sort(key=lambda tup: tup[0], reverse=True)<br> for (count, name) in results:<br>- print "\t%-*s %5d" % (width, name, count)<br>- print ""<br>+ print("\t%-*s %5d" % (width, name, count))<br>+ print("")<br> <br> <br> def load_yaml_config(path):<br>@@ -95,10 +95,10 @@<br> except IOError:<br> # Ignore errors for the optional tests/custom folder.<br> if path != "tests/custom/tests.yaml":<br>- print "Failed to open %s" % path<br>+ print("Failed to open %s" % path)<br> return None<br> except:<br>- print "Unexpected error: %s" % sys.exc_info()[0]<br>+ print("Unexpected error: %s" % sys.exc_info()[0])<br> return None<br> <br> config = yaml.load(f)<br>@@ -108,11 +108,11 @@<br> <br> <br> def main(argv=None):<br>- print "Testsuite Module Usage and Coverage Report"<br>- print ""<br>+ print("Testsuite Module Usage and Coverage Report")<br>+ print("")<br> test_suite = TestSuite()<br>- print "Number of tests:", len(test_suite.tests)<br>- print ""<br>+ print("Number of tests:", len(test_suite.tests))<br>+ print("")<br> test_suite.results_for('tags')<br> test_suite.results_for('test_objects')<br> test_suite.results_for('test_modules')<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/9314">change 9314</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/9314"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: testsuite </div>
<div style="display:none"> Gerrit-Branch: 15 </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: If76c2d3e11e4ab4552d0df7841287c8bb2de7918 </div>
<div style="display:none"> Gerrit-Change-Number: 9314 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Corey Farrell <git@cfware.com> </div>