[asterisk-commits] mjordan: testsuite/asterisk/trunk r3423 - in /asterisk/trunk: lib/python/aste...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Aug 10 09:48:06 CDT 2012
Author: mjordan
Date: Fri Aug 10 09:48:02 2012
New Revision: 3423
URL: http://svnview.digium.com/svn/testsuite?view=rev&rev=3423
Log:
Prevent reactor timeouts from leaving orphaned SIPp processes
This patch does two things:
1. It migrates the SIPp process from using a provided twisted process
protocol (from the utils module) to using a full blown ProcessProtocol.
This lets us kill the process that the ProcessProtocol object manages
in a much easier fashion.
2. When a reactor time out occurs and stop_asterisk is called, the provided
concrete implementation of TestClass in the sipp module will now attempt
to kill any SIPp processes that have failed to exit.
The presence state tests, which manage their own SIPp instances, have also
been modified to kill the SIPp instances if they fail to exit.
Modified:
asterisk/trunk/lib/python/asterisk/sipp.py
asterisk/trunk/tests/channels/SIP/sip_custom_presence/multiple_state_change/run-test
asterisk/trunk/tests/channels/SIP/sip_custom_presence/nominal_state_change/run-test
asterisk/trunk/tests/channels/SIP/sip_custom_presence/non_digium_state_change/run-test
asterisk/trunk/tests/channels/SIP/sip_custom_presence/resubscribe/run-test
Modified: asterisk/trunk/lib/python/asterisk/sipp.py
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/lib/python/asterisk/sipp.py?view=diff&rev=3423&r1=3422&r2=3423
==============================================================================
--- asterisk/trunk/lib/python/asterisk/sipp.py (original)
+++ asterisk/trunk/lib/python/asterisk/sipp.py Fri Aug 10 09:48:02 2012
@@ -59,6 +59,7 @@
self._final_observers = []
self._test_config = test_config
self._current_test = 0
+ self.scenarios = []
if 'fail-on-any' in self._test_config:
self._fail_on_any = self._test_config['fail-on-any']
else:
@@ -75,6 +76,13 @@
self.create_ami_factory()
self.ast[0].cli_exec('sip set debug on')
+
+
+ def stop_asterisk(self):
+ ''' Kill any remaining SIPp scenarios '''
+ for scenario in self.scenarios:
+ if not scenario.exited:
+ scenario.kill()
def ami_connect(self, ami):
@@ -156,7 +164,6 @@
self.stop_reactor()
return result
- scenarios = []
for defined_scenario_set in self._test_config['test-iterations']:
scenario_set = defined_scenario_set['scenarios']
@@ -315,6 +322,68 @@
dl.addCallback(__execute_next)
+class SIPpProtocol(protocol.ProcessProtocol):
+ ''' Class that manages a SIPp instance '''
+
+ def __init__(self, name, stop_deferred):
+ ''' Create a SIPp process
+
+ Keyword Arguments:
+ name - the name of the scenario
+ stop_deferred - a twisted Deferred object that will be called when the
+ process has exited
+ '''
+ self.__name = name
+ self.output = ""
+ self.exitcode = 0
+ self.exited = False
+ self.stderr = []
+ self.__stop_deferred = stop_deferred
+
+ def kill(self):
+ ''' Kill the SIPp scenario '''
+ if not self.exited:
+ LOGGER.warn("Killing SIPp Scenario %s" % self.__name)
+ self.transport.signalProcess('KILL')
+
+ def outReceived(self, data):
+ ''' Override of ProcessProtocol.outReceived '''
+ LOGGER.debug("Received from SIPp scenario %s: %s" % (self.__name, data))
+ self.output += data
+
+ def connectionMade(self):
+ ''' Override of ProcessProtocol.connectionMade '''
+ LOGGER.debug("Connection made to SIPp scenario %s" % (self.__name))
+
+ def errReceived(self, data):
+ ''' Override of ProcessProtocol.errReceived '''
+ # SIPp will send some 'normal' messages to stderr. Buffer them so we
+ # can output them later if we want
+ self.stderr.append(data)
+
+ def processEnded(self, reason):
+ ''' Override of ProcessProtocol.processEnded '''
+ if self.exited:
+ return reason
+
+ self.exited = True
+ message = ""
+ if reason.value and reason.value.exitCode:
+ message = "SIPp scenario %s ended with code %d" % (self.__name, reason.value.exitCode,)
+ self.exitcode = reason.value.exitCode
+ for msg in self.stderr:
+ LOGGER.warn(msg)
+ else:
+ message = "SIPp scenario %s ended " % self.__name
+ try:
+ if not self.__stop_deferred.called:
+ self.__stop_deferred.callback(self)
+ except defer.AlreadyCalledError:
+ pass
+ LOGGER.info(message)
+ return reason
+
+
class SIPpScenario:
"""
A SIPp based scenario for the Asterisk testsuite.
@@ -359,6 +428,14 @@
self.default_port = 5061
self.sipp = TestSuiteUtils.which("sipp")
self.passed = False
+ self.exited = False
+ self._process = None
+
+ def kill(self):
+ """ Kill the executing SIPp scenario """
+ if self._process:
+ self._process.kill()
+ return
def run(self, test_case = None):
""" Execute a SIPp scenario
@@ -375,31 +452,24 @@
has exited.
"""
- def __output_callback(result):
- """ Callback from getProcessOutputAndValue """
- out, err, code = result
- LOGGER.debug("Launching SIPp Scenario %s exited %d"
- % (self.scenario['scenario'], code))
- if (code == 0):
+ def __scenario_callback(result):
+ self.exited = True
+ if (result.exitcode == 0):
self.passed = True
LOGGER.info("SIPp Scenario %s Exited" % (self.scenario['scenario']))
else:
- LOGGER.warning("SIPp Scenario %s Failed [%d, %s]" % (self.scenario['scenario'], code, err))
- self.__exit_deferred.callback(self)
-
- def __error_callback(result):
- """ Errback from getProcessOutputAndValue """
- out, err, code = result
- LOGGER.warning("SIPp Scenario %s Failed [%d, %s]" % (self.scenario['scenario'], code, err))
- self.__exit_deferred.callback(self)
-
- def __evalute_scenario_results(result):
+ LOGGER.warning("SIPp Scenario %s Failed [%d]" % (self.scenario['scenario'], result.exitcode))
+ self._our_exit_deferred.callback(self)
+ return result
+
+ def __evaluate_scenario_results(result):
""" Convenience function. If the test case is injected into this method,
then auto-fail the test if the scenario fails. """
if not self.passed:
LOGGER.warning("SIPp Scenario %s Failed" % self.scenario['scenario'])
self.__test_case.passed = False
self.__test_case.stop_reactor()
+ return result
sipp_args = [
self.sipp, '127.0.0.1',
@@ -425,15 +495,18 @@
LOGGER.info("Executing SIPp scenario: %s" % self.scenario['scenario'])
LOGGER.debug(sipp_args)
- self.__exit_deferred = defer.Deferred()
-
- df = utils.getProcessOutputAndValue(sipp_args[0], sipp_args, {"TERM" : "vt100",}, None, None)
- df.addCallbacks(__output_callback, __error_callback)
+ self._our_exit_deferred = defer.Deferred()
+
+ exit_deferred = defer.Deferred()
+ exit_deferred.addCallback(__scenario_callback)
if test_case:
self.__test_case = test_case
- df.addCallback(__evalute_scenario_results)
-
- return self.__exit_deferred
+ exit_deferred.addCallback(__evaluate_scenario_results)
+
+ self._process = SIPpProtocol(self.scenario['scenario'], exit_deferred)
+ reactor.spawnProcess(self._process, sipp_args[0], sipp_args, {"TERM" : "vt100",}, None, None)
+
+ return self._our_exit_deferred
class SIPpTest(TestCase):
"""
@@ -482,6 +555,16 @@
self.scenarios = scenarios
self.result = []
self.create_asterisk()
+ self._scenario_objects = []
+
+
+ def stop_asterisk(self):
+ ''' Kill any scenarios still in existance '''
+ for scenario in self._scenario_objects:
+ if not scenario.exited:
+ LOGGER.warn("SIPp Scenario %s has not exited; killing" % scenario.name)
+ scenario.kill()
+
def run(self):
"""
@@ -510,6 +593,7 @@
if not '-p' in s:
s['-p'] = str(default_port)
scenario = SIPpScenario(self.test_dir, s)
+ self._scenario_objects.append(scenario)
df = scenario.run(self)
df.addCallback(__check_result)
deferds.append(df)
Modified: asterisk/trunk/tests/channels/SIP/sip_custom_presence/multiple_state_change/run-test
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/SIP/sip_custom_presence/multiple_state_change/run-test?view=diff&rev=3423&r1=3422&r2=3423
==============================================================================
--- asterisk/trunk/tests/channels/SIP/sip_custom_presence/multiple_state_change/run-test (original)
+++ asterisk/trunk/tests/channels/SIP/sip_custom_presence/multiple_state_change/run-test Fri Aug 10 09:48:02 2012
@@ -102,6 +102,11 @@
ami.registerEvent("TestEvent", self.inspectPresence)
self.runSippTest()
+ def stop_asterisk(self):
+ ''' Kill the SIPp test if it didn't exit '''
+ if not self.sipTest.exited:
+ self.sipTest.kill()
+
def run(self):
TestCase.run(self)
self.create_ami_factory()
Modified: asterisk/trunk/tests/channels/SIP/sip_custom_presence/nominal_state_change/run-test
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/SIP/sip_custom_presence/nominal_state_change/run-test?view=diff&rev=3423&r1=3422&r2=3423
==============================================================================
--- asterisk/trunk/tests/channels/SIP/sip_custom_presence/nominal_state_change/run-test (original)
+++ asterisk/trunk/tests/channels/SIP/sip_custom_presence/nominal_state_change/run-test Fri Aug 10 09:48:02 2012
@@ -77,6 +77,11 @@
if self.num_notifies == 2:
self.notifyPassed = True
+ def stop_asterisk(self):
+ ''' Kill the SIPp test if it didn't exit '''
+ if not self.sipTest.exited:
+ self.sipTest.kill()
+
def ami_connect(self, ami):
self.ast[ami.id].cli_exec("sip set debug on")
ami.registerEvent("TestEvent", self.inspectPresence)
Modified: asterisk/trunk/tests/channels/SIP/sip_custom_presence/non_digium_state_change/run-test
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/SIP/sip_custom_presence/non_digium_state_change/run-test?view=diff&rev=3423&r1=3422&r2=3423
==============================================================================
--- asterisk/trunk/tests/channels/SIP/sip_custom_presence/non_digium_state_change/run-test (original)
+++ asterisk/trunk/tests/channels/SIP/sip_custom_presence/non_digium_state_change/run-test Fri Aug 10 09:48:02 2012
@@ -68,6 +68,11 @@
ami.registerEvent("UserEvent", self.originateComplete)
self.runSippTest()
+ def stop_asterisk(self):
+ ''' Kill the SIPp test if it didn't exit '''
+ if not self.sipTest.exited:
+ self.sipTest.kill()
+
def run(self):
TestCase.run(self)
self.create_ami_factory()
Modified: asterisk/trunk/tests/channels/SIP/sip_custom_presence/resubscribe/run-test
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/channels/SIP/sip_custom_presence/resubscribe/run-test?view=diff&rev=3423&r1=3422&r2=3423
==============================================================================
--- asterisk/trunk/tests/channels/SIP/sip_custom_presence/resubscribe/run-test (original)
+++ asterisk/trunk/tests/channels/SIP/sip_custom_presence/resubscribe/run-test Fri Aug 10 09:48:02 2012
@@ -120,6 +120,13 @@
ami.registerEvent("TestEvent", self.inspectPresence)
self.runSippTest()
+ def stop_asterisk(self):
+ ''' Kill the SIPp test if it didn't exit '''
+ if not self.sipTestInitial.exited:
+ self.sipTestInitial.kill()
+ if not self.sipTestResubscribe.exited:
+ self.sipTestResubscribe.kill()
+
def run(self):
TestCase.run(self)
self.create_ami_factory()
More information about the asterisk-commits
mailing list