[asterisk-commits] mjordan: testsuite/asterisk/trunk r3188 - /asterisk/trunk/lib/python/asterisk/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Apr 17 18:05:48 CDT 2012
Author: mjordan
Date: Tue Apr 17 18:05:44 2012
New Revision: 3188
URL: http://svnview.digium.com/svn/testsuite?view=rev&rev=3188
Log:
Update the pre-/post-condition check framework to support twisted
This patch updates the pre-/post-condition checking framework in the
Asterisk Test Suite to use the twisted asynchronous framework for its
CLI/AMI commands. This was necessary, as the starting/stopping
of Asterisk now expects things that explicitly need to be involved
in the process to be in the deferred callback chain.
Review: https://reviewboard.asterisk.org/r/1831
Modified:
asterisk/trunk/lib/python/asterisk/ChannelTestCondition.py
asterisk/trunk/lib/python/asterisk/FdTestCondition.py
asterisk/trunk/lib/python/asterisk/LockTestCondition.py
asterisk/trunk/lib/python/asterisk/SipDialogTestCondition.py
asterisk/trunk/lib/python/asterisk/TestCase.py
asterisk/trunk/lib/python/asterisk/TestConditions.py
asterisk/trunk/lib/python/asterisk/ThreadTestCondition.py
Modified: asterisk/trunk/lib/python/asterisk/ChannelTestCondition.py
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/lib/python/asterisk/ChannelTestCondition.py?view=diff&rev=3188&r1=3187&r2=3188
==============================================================================
--- asterisk/trunk/lib/python/asterisk/ChannelTestCondition.py (original)
+++ asterisk/trunk/lib/python/asterisk/ChannelTestCondition.py Tue Apr 17 18:05:44 2012
@@ -1,6 +1,6 @@
#!/usr/bin/env python
'''
-Copyright (C) 2011, Digium, Inc.
+Copyright (C) 2011-2012, Digium, Inc.
Matt Jordan <mjordan at digium.com>
This program is free software, distributed under the terms of
@@ -11,6 +11,7 @@
import logging.config
import unittest
+from twisted.internet import defer
from TestConditions import TestCondition
logger = logging.getLogger(__name__)
@@ -32,10 +33,8 @@
self.allowed_channels = test_config.config['allowedchannels']
def evaluate(self, related_test_condition = None):
- for ast in self.ast:
- """ For logging / debug purposes, do a full core show channels """
- channel_lines = ast.cli_exec('core show channels')
- channel_tokens = channel_lines.strip().split('\n')
+ def __channel_callback(result):
+ channel_tokens = result.output.strip().split('\n')
active_channels = 0
for token in channel_tokens:
if 'active channels' in token:
@@ -43,7 +42,18 @@
active_channels = int(active_channel_tokens[0].strip())
if active_channels > self.allowed_channels:
super(ChannelTestCondition, self).failCheck(
- 'Detected number of active channels %d is greater than the allowed %d on Asterisk %s' % (active_channels, self.allowed_channels, ast.host))
- """ Set to pass if we haven't detected any failures """
+ 'Detected number of active channels %d is greater than the allowed %d on Asterisk %s'
+ % (active_channels, self.allowed_channels, result.host))
+ return result
+
+ def __raise_finished(result):
+ self.__finished_deferred.callback(self)
+ return result
+
+ self.__finished_deferred = defer.Deferred()
+ # Set to pass and let a failure override
super(ChannelTestCondition, self).passCheck()
+ defer.DeferredList([ast.cli_exec('core show channels').addCallback(__channel_callback) for ast in self.ast]
+ ).addCallback(__raise_finished)
+ return self.__finished_deferred
Modified: asterisk/trunk/lib/python/asterisk/FdTestCondition.py
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/lib/python/asterisk/FdTestCondition.py?view=diff&rev=3188&r1=3187&r2=3188
==============================================================================
--- asterisk/trunk/lib/python/asterisk/FdTestCondition.py (original)
+++ asterisk/trunk/lib/python/asterisk/FdTestCondition.py Tue Apr 17 18:05:44 2012
@@ -1,6 +1,6 @@
#!/usr/bin/env python
'''
-Copyright (C) 2011, Digium, Inc.
+Copyright (C) 2011-2012, Digium, Inc.
Matt Jordan <mjordan at digium.com>
This program is free software, distributed under the terms of
@@ -11,6 +11,7 @@
import logging.config
import unittest
+from twisted.internet import defer
from TestConditions import TestCondition
logger = logging.getLogger(__name__)
@@ -47,73 +48,83 @@
self.add_build_option("DEBUG_FD_LEAKS", "1")
def get_file_descriptors(self, ast):
- if ast == None:
- return
+ def __show_fd_callback(result):
+ lines = result.output
+ if 'No such command' in lines:
+ return result
+ if 'Unable to connect to remote asterisk' in lines:
+ return result
- lines = ast.cli_exec("core show fd")
- if 'No such command' in lines:
- return
- if 'Unable to connect to remote asterisk' in lines:
- return
+ """ Trim off the first and last lines """
+ lines = lines[lines.find('\n'):].strip()
+ lines = lines[:lines.find("Asterisk ending")].strip()
+ line_tokens = lines.split('\n')
+ fds = []
+ for line in line_tokens:
+ # chan_sip is going to create sockets for the active channels and won't close them until
+ # the dialog is reclaimed - 32 seconds after the test. We ignore the UDP socket file
+ # descriptors because of this.
+ if 'socket(PF_INET,SOCK_DGRAM,"udp")' in line:
+ logger.debug("Ignoring created UDP socket: " + line)
+ continue
+ # If we have MALLOC_DEBUG on and are writing out to the mmlog, ignore
+ if '__ast_mm_init' in line:
+ logger.debug("Ignoring malloc debug: " + line)
+ continue
+ fd = FileDescriptor(line)
+ if fd.number != -1:
+ logger.debug("Tracking %d [%s]", fd.number, fd.info)
+ fds.append(fd)
+ else:
+ logger.warn("Failed to parse [%s] into file descriptor object" % line)
+ self.file_descriptors[result.host] = fds
- """ Trim off the first and last lines """
- lines = lines[lines.find('\n'):].strip()
- lines = lines[:lines.find("Asterisk ending")].strip()
- line_tokens = lines.split('\n')
- fds = []
- for line in line_tokens:
- """
- chan_sip is going to create sockets for the active channels and won't close them until
- the dialog is reclaimed - 32 seconds after the test. We ignore the UDP socket file
- descriptors because of this.
- """
- if 'socket(PF_INET,SOCK_DGRAM,"udp")' in line:
- logger.debug("Ignoring created UDP socket: " + line)
- continue
- """
- If we have MALLOC_DEBUG on and are writing out to the mmlog, ignore
- """
- if '__ast_mm_init' in line:
- logger.debug("Ignoring malloc debug: " + line)
- continue
- fd = FileDescriptor(line)
- if fd.number != -1:
- logger.debug("Tracking %d [%s]", fd.number, fd.info)
- fds.append(fd)
- else:
- logger.warn("Failed to parse [%s] into file descriptor object" % line)
- self.file_descriptors[ast.host] = fds
+ return ast.cli_exec("core show fd").addCallback(__show_fd_callback)
class FdPreTestCondition(FdTestCondition):
def evaluate(self, related_test_condition = None):
- for ast in self.ast:
- super(FdPreTestCondition, self).get_file_descriptors(ast)
+ def __raise_finished(result):
+ self.__finished_deferred.callback(self)
+ return result
- """
- Automatically pass the pre-test condition - whatever file descriptors are currently
- open are needed by Asterisk and merely expected to exist when the test is finished
- """
+ #Automatically pass the pre-test condition - whatever file descriptors are currently
+ #open are needed by Asterisk and merely expected to exist when the test is finished
super(FdPreTestCondition, self).passCheck()
+
+ defer.DeferredList([super(FdPreTestCondition, self).get_file_descriptors(ast)
+ for ast in self.ast]).addCallback(__raise_finished)
+
+ self.__finished_deferred = defer.Deferred()
+ return self.__finished_deferred
class FdPostTestCondition(FdTestCondition):
def evaluate(self, related_test_condition = None):
+ def __file_descriptors_obtained(result):
+ for ast_host in related_test_condition.file_descriptors.keys():
+ if not ast_host in self.file_descriptors:
+ super(FdPostTestCondition, self).failCheck("Asterisk host in pre-test check [%s]"
+ " not found in post-test check" % ast_host)
+ else:
+ # Find all file descriptors in pre-check not in post-check
+ for fd in related_test_condition.file_descriptors[ast_host]:
+ if (len([f for f in self.file_descriptors[ast_host] if fd.number == f.number]) == 0):
+ super(FdPostTestCondition, self).failCheck("Failed to find file descriptor %d [%s] in "
+ "post-test check" % (fd.number, fd.info))
+ # Find all file descriptors in post-check not in pre-check
+ for fd in self.file_descriptors[ast_host]:
+ if (len([f for f in related_test_condition.file_descriptors[ast_host] if fd.number == f.number]) == 0):
+ super(FdPostTestCondition, self).failCheck("Failed to find file descriptor %d [%s] in "
+ "pre-test check" % (fd.number, fd.info))
+ super(FdPostTestCondition, self).passCheck()
+ self.__finished_deferred.callback(self)
+ return result
+
if related_test_condition == None:
super(FdPostTestCondition, self).failCheck("No pre-test condition object provided")
return
- for ast in self.ast:
- super(FdPostTestCondition, self).get_file_descriptors(ast)
+ defer.DeferredList([super(FdPostTestCondition, self).get_file_descriptors(ast) for ast in self.ast]
+ ).addCallback(__file_descriptors_obtained)
+ self.__finished_deferred = defer.Deferred()
+ return self.__finished_deferred
- for ast_host in related_test_condition.file_descriptors.keys():
- if not ast_host in self.file_descriptors:
- super(FdPostTestCondition, self).failCheck("Asterisk host in pre-test check [%s] not found in post-test check" % ast_host)
- else:
- for fd in related_test_condition.file_descriptors[ast_host]:
- match = [f for f in self.file_descriptors[ast_host] if fd.number == f.number]
- if (len(match) == 0):
- super(FdPostTestCondition, self).failCheck("Failed to find file descriptor %d [%s] in post-test check" % (fd.number, fd.info))
- for fd in self.file_descriptors[ast_host]:
- match = [f for f in related_test_condition.file_descriptors[ast_host] if fd.number == f.number]
- if (len(match) == 0):
- super(FdPostTestCondition, self).failCheck("Failed to find file descriptor %d [%s] in pre-test check" % (fd.number, fd.info))
- super(FdPostTestCondition, self).passCheck()
Modified: asterisk/trunk/lib/python/asterisk/LockTestCondition.py
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/lib/python/asterisk/LockTestCondition.py?view=diff&rev=3188&r1=3187&r2=3188
==============================================================================
--- asterisk/trunk/lib/python/asterisk/LockTestCondition.py (original)
+++ asterisk/trunk/lib/python/asterisk/LockTestCondition.py Tue Apr 17 18:05:44 2012
@@ -1,6 +1,6 @@
#!/usr/bin/env python
'''
-Copyright (C) 2011, Digium, Inc.
+Copyright (C) 2011-2012, Digium, Inc.
Matt Jordan <mjordan at digium.com>
This program is free software, distributed under the terms of
@@ -11,6 +11,7 @@
import logging.config
import unittest
+from twisted.internet import defer
from TestConditions import TestCondition
logger = logging.getLogger(__name__)
@@ -153,43 +154,55 @@
self.add_build_option("DEBUG_THREADS", "1")
def __get_locks(self, ast):
- locks = ast.cli_exec("core show locks", True)
- """ The first 6 lines are header information - look for a return thread ID """
- if "=== Thread ID:" in locks:
- locks = locks[locks.find("=== Thread ID:"):]
- lockTokens = locks.split("=== -------------------------------------------------------------------")
- for token in lockTokens:
- if "Thread ID" in token:
- try:
- obj = LockSequence()
- obj.parseLockSequence(token)
- t = ast.host, obj
- self.locks.append(t)
- except:
- logger.warning("Unable to parse lock information into a manageable object:\n%s" % token)
+ """ Build the locks for an instance of Asterisk
+ Returns:
+ A deferred for when the locks are built for a given instance
+ """
+ def __show_locks_callback(result):
+ locks = result.output
+ # The first 6 lines are header information - look for a return thread ID
+ if "=== Thread ID:" in locks:
+ locks = locks[locks.find("=== Thread ID:"):]
+ lockTokens = locks.split("=== -------------------------------------------------------------------")
+ for token in lockTokens:
+ if "Thread ID" in token:
+ try:
+ obj = LockSequence()
+ obj.parseLockSequence(token)
+ t = result.host, obj
+ self.locks.append(t)
+ except:
+ logger.warning("Unable to parse lock information into a manageable object:\n%s" % token)
+ return result
+
+ return ast.cli_exec("core show locks").addCallback(__show_locks_callback)
def evaluate(self, related_test_condition = None):
- """ Build up the locks for each instance of asterisk """
- for ast in self.ast:
- self.__get_locks(ast)
-
- if (len(self.locks) > 0):
- """
- Sometimes, a lock will be held at the end of a test run (typically a logger RDLCK). Only
- report a held lock as a failure if the thread is waiting for another lock - that would
- indicate that we may be in a deadlock situation. Since that shouldnt happen either
- before or after a test run, treat that as an error.
- """
- for lockPair in self.locks:
- logger.info("Detected locks on Asterisk instance: %s" % lockPair[0])
- logger.info("Lock trace: %s" % str(lockPair[1]))
- for lock in lockPair[1].locks:
- if not lock.held:
- super(LockTestCondition, self).failCheck("Lock detected in a waiting state")
-
- if super(LockTestCondition, self).getStatus() == 'Inconclusive':
- super(LockTestCondition, self).passCheck()
-
+ def __lock_info_obtained(result):
+ if (len(self.locks) > 0):
+ """
+ Sometimes, a lock will be held at the end of a test run (typically a logger RDLCK). Only
+ report a held lock as a failure if the thread is waiting for another lock - that would
+ indicate that we may be in a deadlock situation. Since that shouldnt happen either
+ before or after a test run, treat that as an error.
+ """
+ for lockPair in self.locks:
+ logger.info("Detected locks on Asterisk instance: %s" % lockPair[0])
+ logger.info("Lock trace: %s" % str(lockPair[1]))
+ for lock in lockPair[1].locks:
+ if not lock.held:
+ super(LockTestCondition, self).failCheck("Lock detected in a waiting state")
+
+ if super(LockTestCondition, self).getStatus() == 'Inconclusive':
+ super(LockTestCondition, self).passCheck()
+ self.__finished_deferred.callback(self)
+ return result
+
+ # Build up the locks for each instance of asterisk
+ defer.DeferredList([self.__get_locks(ast) for ast in self.ast]
+ ).addCallback(__lock_info_obtained)
+ self.__finished_deferred = defer.Deferred()
+ return self.__finished_deferred
class AstMockObjectPassed(object):
def __init__(self):
Modified: asterisk/trunk/lib/python/asterisk/SipDialogTestCondition.py
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/lib/python/asterisk/SipDialogTestCondition.py?view=diff&rev=3188&r1=3187&r2=3188
==============================================================================
--- asterisk/trunk/lib/python/asterisk/SipDialogTestCondition.py (original)
+++ asterisk/trunk/lib/python/asterisk/SipDialogTestCondition.py Tue Apr 17 18:05:44 2012
@@ -1,6 +1,6 @@
#!/usr/bin/env python
'''
-Copyright (C) 2011, Digium, Inc.
+Copyright (C) 2011-2012, Digium, Inc.
Matt Jordan <mjordan at digium.com>
This program is free software, distributed under the terms of
@@ -14,6 +14,7 @@
from TestConditions import TestCondition
from starpy import manager
+from twisted.internet import defer
logger = logging.getLogger(__name__)
@@ -27,6 +28,8 @@
def __init__(self, test_config):
super(SipDialogTestCondition, self).__init__(test_config)
+ # a dictionary of ast objects to a dictionary of SIP dialogs and a list of their history
+ self.dialogs_history = {}
def __get_dialog_names(self, objects):
inObjects = False
@@ -40,19 +43,48 @@
return dialogNames
def get_sip_dialogs(self, ast):
- dialogNames = []
- dialogsHistory = {}
- objects = ast.cli_exec("sip show objects", True)
- dialogNames = self.__get_dialog_names(objects)
-
- for dn in dialogNames:
- logger.debug("Retrieving history for SIP dialog %s" % dn)
- rawHistory = ast.cli_exec("sip show history %s" % dn, True)
+ """ Build the dialog history and objects for a particular Asterisk instance """
+ def __show_objects_callback(result):
+ """ Callback for sip show objects """
+ logger.debug(result.output)
+ dialogNames = self.__get_dialog_names(result.output)
+ logger.debug(dialogNames)
+ if not dialogNames:
+ logger.debug("No SIP history found for Asterisk instance %s" % ast.host)
+ self.__finished_deferred.callback(self.__ast)
+ return result
+
+ deferds = []
+ self.__history_requests = []
+ for dn in dialogNames:
+ logger.debug("Retrieving history for SIP dialog %s" % dn)
+ cmd = "sip show history %s" % dn
+ self.__history_requests.append(cmd)
+ deferds.append(ast.cli_exec(cmd).addCallback(__show_history_callback))
+ defer.DeferredList(deferds).addCallback(__history_complete)
+ return result
+
+ def __show_history_callback(result):
+ """ Callback for sip show history """
+ # Get the Call ID from the result
+ call_id = result.cli_cmd.replace("sip show history", "").strip()
+ rawHistory = result.output
+ logger.debug(result.output)
if 'No such SIP Call ID' not in rawHistory:
- """ dialog got disposed before we could get its history; ignore """
- dialogsHistory[dn] = rawHistory.split('\n')
-
- return dialogsHistory
+ # dialog got disposed before we could get its history; ignore
+ self.dialogs_history[self.__ast.host][call_id] = rawHistory.split('\n')
+ return result
+
+ def __history_complete(result):
+ self.__finished_deferred.callback(self.__ast)
+ return result
+
+ self.__ast = ast
+ self.dialogs_history[self.__ast.host] = {}
+ self.__finished_deferred = defer.Deferred()
+ ast.cli_exec("sip show objects").addCallback(__show_objects_callback)
+
+ return self.__finished_deferred
class SipDialogPreTestCondition(SipDialogTestCondition):
"""
@@ -64,17 +96,38 @@
super(SipDialogPreTestCondition, self).__init__(test_config)
def evaluate(self, related_test_condition = None):
- for ast in self.ast:
- ast.cli_exec("sip set history on")
- dialogsHistory = super(SipDialogPreTestCondition, self).get_sip_dialogs(ast)
-
+ def __history_finished(result):
+ for ast in self.ast:
+ if ast.host == result.host:
+ __get_dialogs(ast)
+ return result
+ logger.warning("Unable to determine Asterisk instance from CLI command run on host %s" % result.host)
+ return result
+
+ def __get_dialogs(ast):
+ super(SipDialogPreTestCondition, self).get_sip_dialogs(ast).addCallback(__dialogs_obtained)
+
+ def __dialogs_obtained(result):
+ dialogsHistory = self.dialogs_history[result.host]
if len(dialogsHistory) > 0:
- """ If any dialogs are present before test execution, something funny is going on """
+ # If any dialogs are present before test execution, something funny is going on
super(SipDialogPreTestCondition, self).failCheck(
- "%d dialogs were detected in Asterisk %s before test execution" % (len(dialogsHistory), ast.host))
+ "%d dialogs were detected in Asterisk %s before test execution"
+ % (len(dialogsHistory), result.host))
else:
super(SipDialogPreTestCondition, self).passCheck()
-
+ self.__counter += 1
+ if self.__counter == len(self.ast):
+ # All asterisk instances have been checked
+ self.__finished_deferred.callback(self)
+ return result
+
+ self.__counter = 0
+ self.__finished_deferred = defer.Deferred()
+ # Turn on history and check for dialogs
+ for ast in self.ast:
+ ast.cli_exec("sip set history on").addCallback(__history_finished)
+ return self.__finished_deferred
class SipDialogPostTestCondition(SipDialogTestCondition):
"""
@@ -97,37 +150,54 @@
self.sipHistorySequence = test_config.config['sipHistoryRequirements']
def evaluate(self, related_test_condition = None):
-
- for ast in self.ast:
+ def __get_dialogs():
+ self.__counter += 1
+ if self.__counter == len(self.ast):
+ self.__finished_deferred.callback(self)
+ return
+ super(SipDialogPostTestCondition, self).get_sip_dialogs(
+ self.ast[self.__counter]).addCallback(__dialogs_obtained)
+
+ def __dialogs_obtained(result):
sipHistoryRequirements = {}
- dialogsHistory = super(SipDialogPostTestCondition, self).get_sip_dialogs(ast)
-
- """ Set up the history statements to look for in each dialog history """
+ dialogsHistory = self.dialogs_history[self.ast[self.__counter].host]
+ if not dialogsHistory:
+ __get_dialogs()
+ return result
+
+ # Set up the history statements to look for in each dialog history
for dialogName in dialogsHistory.keys():
sipHistoryCheck = {}
for h in self.sipHistorySequence:
sipHistoryCheck[h] = False
sipHistoryRequirements[dialogName] = sipHistoryCheck
- """ Assume we pass the check. This will be overriden if any history check fails """
+ # Assume we pass the check. This will be overriden if any history check fails
super(SipDialogPostTestCondition, self).passCheck()
- if (len(dialogsHistory) > 0):
- for dialog, history in dialogsHistory.items():
- scheduled = False
- for h in history:
- if "SchedDestroy" in h:
- scheduled = True
- for req in sipHistoryRequirements[dialog].keys():
- if req in h:
- sipHistoryRequirements[dialog][req] = True
-
- if not scheduled:
+ for dialog, history in dialogsHistory.items():
+ scheduled = False
+ for h in history:
+ if "SchedDestroy" in h:
+ scheduled = True
+ for req in sipHistoryRequirements[dialog].keys():
+ if req in h:
+ sipHistoryRequirements[dialog][req] = True
+ if not scheduled:
+ super(SipDialogPostTestCondition, self).failCheck(
+ "Dialog %s in Asterisk instance %s not scheduled for destruction"
+ % (dialog, self.ast[self.__counter].host))
+ for req in sipHistoryRequirements[dialog].keys():
+ if sipHistoryRequirements[dialog][req] == False:
super(SipDialogPostTestCondition, self).failCheck(
- "Dialog %s in Asterisk instance %s not scheduled for destruction" % (dialog, ast.host))
- for req in sipHistoryRequirements[dialog].keys():
- if sipHistoryRequirements[dialog][req] == False:
- super(SipDialogPostTestCondition, self).failCheck(
- "Dialog %s in Asterisk instance %s did not have required step in history: %s" % (dialog, ast.host, req))
+ "Dialog %s in Asterisk instance %s did not have required step in history: %s"
+ % (dialog, self.ast[self.__counter].host, req))
+ __get_dialogs()
+ return result
+
+ self.__finished_deferred = defer.Deferred()
+ self.__counter = -1
+ __get_dialogs()
+ return self.__finished_deferred
class TestConfig(object):
def __init__(self):
Modified: asterisk/trunk/lib/python/asterisk/TestCase.py
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/lib/python/asterisk/TestCase.py?view=diff&rev=3188&r1=3187&r2=3188
==============================================================================
--- asterisk/trunk/lib/python/asterisk/TestCase.py (original)
+++ asterisk/trunk/lib/python/asterisk/TestCase.py Tue Apr 17 18:05:44 2012
@@ -1,6 +1,6 @@
#!/usr/bin/env python
'''
-Copyright (C) 2010, Digium, Inc.
+Copyright (C) 2010-2012, Digium, Inc.
Paul Belanger <pabelanger at digium.com>
This program is free software, distributed under the terms of
@@ -229,8 +229,11 @@
def __perform_pre_checks(result):
""" Execute the pre-condition checks """
- self.testConditionController.evaluate_pre_checks()
- return result
+ df = self.testConditionController.evaluate_pre_checks()
+ if df is None:
+ return result
+ else:
+ return df
def __run_callback(result):
""" Notify the test that we are running """
@@ -280,24 +283,31 @@
# This should already be called when the reactor is being terminated.
# If we couldn't stop the instance of Asterisk, there isn't much else to do
# here other then complain
+ self.__stop_deferred.callback(self)
return result
- # Call the overridable method
- self.stop_asterisk()
-
- self.testConditionController.evaluate_post_checks()
-
- # Gather up the stopped defers; check success failure of stopping when
- # all instances of Asterisk have stopped
- stop_defers = []
- for index, item in enumerate(self.ast):
- logger.info("Stopping Asterisk instance %d" % (index + 1))
- temp_defer = self.ast[index].stop()
- stop_defers.append(temp_defer)
-
- d = defer.DeferredList(stop_defers, consumeErrors=True)
- d.addCallback(__check_success_failure)
- return d
+ def __stop_instances(result):
+ # Call the overridable method
+ self.stop_asterisk()
+ # Gather up the stopped defers; check success failure of stopping when
+ # all instances of Asterisk have stopped
+ stop_defers = []
+ for index, item in enumerate(self.ast):
+ logger.info("Stopping Asterisk instance %d" % (index + 1))
+ temp_defer = self.ast[index].stop()
+ stop_defers.append(temp_defer)
+
+ d = defer.DeferredList(stop_defers, consumeErrors=True)
+ d.addCallback(__check_success_failure)
+ return result
+
+ self.__stop_deferred = defer.Deferred()
+ df = self.testConditionController.evaluate_post_checks()
+ if df:
+ df.addCallback(__stop_instances)
+ else:
+ __stop_instances(None)
+ return self.__stop_deferred
def stop_reactor(self):
"""
Modified: asterisk/trunk/lib/python/asterisk/TestConditions.py
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/lib/python/asterisk/TestConditions.py?view=diff&rev=3188&r1=3187&r2=3188
==============================================================================
--- asterisk/trunk/lib/python/asterisk/TestConditions.py (original)
+++ asterisk/trunk/lib/python/asterisk/TestConditions.py Tue Apr 17 18:05:44 2012
@@ -1,6 +1,6 @@
#!/usr/bin/env python
'''
-Copyright (C) 2011, Digium, Inc.
+Copyright (C) 2011-2012, Digium, Inc.
Matt Jordan <mjordan at digium.com>
This program is free software, distributed under the terms of
@@ -13,6 +13,7 @@
from buildoptions import AsteriskBuildOptions
from TestConfig import TestConfig
+from twisted.internet import defer
logger = logging.getLogger(__name__)
@@ -105,33 +106,75 @@
def evaluate_pre_checks(self):
"""
Evaluate the pre-test conditions
- """
- if (len(self.__prechecks) > 0):
- logger.debug("Evaluating pre checks")
- self.__evaluate_checks(self.__prechecks)
+
+ Returns:
+ A deferred that will be raised when all pre-checks have finished,
+ or None if no pre-checks exist
+ """
+ if (not self.__prechecks):
+ return None
+
+ logger.debug("Evaluating pre checks")
+ self.__finished_deferred = defer.Deferred()
+ self.__evaluate_check(self.__prechecks, 0)
+ return self.__finished_deferred
def evaluate_post_checks(self):
"""
Evaluate the post-test conditions
- """
- if (len(self.__postchecks) > 0):
- time.sleep(10)
- logger.debug("Evaluating post checks")
- self.__evaluate_checks(self.__postchecks)
-
- def __evaluate_checks(self, check_list):
+
+ Returns:
+ A deferred that will be raised when all post-checks have finished,
+ or None if no post-checks exist
+ """
+ if (not self.__postchecks):
+ return None
+
+ logger.debug("Evaluating post checks")
+ self.__finished_deferred = defer.Deferred()
+ self.__evaluate_check(self.__postchecks, 0)
+ return self.__finished_deferred
+
+ def __evaluate_check(self, check_list, counter):
""" Register the instances of Asterisk and evaluate """
- for check in check_list:
- if (check[0].check_build_options()):
- for ast in self.__ast:
- check[0].register_asterisk_instance(ast)
- if (check[0].getEnabled()):
- logger.debug("Evaluating %s" % check[0].getName())
- if (check[1] != None):
- check[0].evaluate(check[1])
- else:
- check[0].evaluate()
- self.__check_observers(check[0])
+ def __evaluate_callback(result):
+ self.__check_observers(result)
+ self.__check_list_counter += 1
+ self.__evaluate_check(self.__check_list, self.__check_list_counter)
+ return result
+
+ def __evaluate_errback(result):
+ logger.warning("Failed to evaluate condition check %s" % str(result))
+ self.__check_observers(result)
+ self.__check_list_counter += 1
+ self.__evaluate_check(self.__check_list, self.__check_list_counter)
+ return result
+
+ if (counter >= len(check_list)):
+ # All done - raise the finished deferred
+ self.__finished_deferred.callback(self)
+ return
+
+ self.__check_list = check_list
+ self.__check_list_counter = counter
+ # A check object is a tuple of a pre/post condition check, and either
+ # a matching check object used in the evaluation, or None
+ check = check_list[counter]
+
+ # Check to see if the build supports this condition check
+ if not (check[0].check_build_options()):
+ self.__check_list_counter += 1
+ self.__evaluate_check(self.__check_list, self.__check_list_counter)
+
+ for ast in self.__ast:
+ check[0].register_asterisk_instance(ast)
+ if (check[0].getEnabled()):
+ logger.debug("Evaluating %s" % check[0].getName())
+ if (check[1] != None):
+ df = check[0].evaluate(check[1])
+ else:
+ df = check[0].evaluate()
+ df.addCallbacks(__evaluate_callback, __evaluate_errback)
def __check_observers(self, test_condition):
for observerTuple in self.__observers:
@@ -227,11 +270,15 @@
Derived classes must implement this method and check their test condition
here. If the test condition passes they should call passCheck, otherwise they
- should call failCheck.
+ should call failCheck. Each test condition must return a twisted deferred, and
+ raise a callback on the deferred when the condition is finished being evaluated.
+ They may raise an errback if a serious error occurs in the evaluation.
Keyword arguments:
related_test_condition -- A test condition object that is related to this one. Provided if specified
when this test condition is registered to the test condition controller.
+ Returns:
+ A twisted deferred object
"""
pass
Modified: asterisk/trunk/lib/python/asterisk/ThreadTestCondition.py
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/lib/python/asterisk/ThreadTestCondition.py?view=diff&rev=3188&r1=3187&r2=3188
==============================================================================
--- asterisk/trunk/lib/python/asterisk/ThreadTestCondition.py (original)
+++ asterisk/trunk/lib/python/asterisk/ThreadTestCondition.py Tue Apr 17 18:05:44 2012
@@ -1,6 +1,6 @@
#!/usr/bin/env python
'''
-Copyright (C) 2011, Digium, Inc.
+Copyright (C) 2011-2012, Digium, Inc.
Matt Jordan <mjordan at digium.com>
This program is free software, distributed under the terms of
@@ -11,6 +11,7 @@
import logging.config
from TestConditions import TestCondition
from version import AsteriskVersion
+from twisted.internet import defer
logger = logging.getLogger(__name__)
@@ -81,16 +82,27 @@
super(ThreadPreTestCondition, self).__init__(test_config)
def evaluate(self, related_test_condition = None):
- for ast in self.ast:
- threads = ast.cli_exec("core show threads", True)
+ """ Override of TestCondition:evaluate """
+ def __show_threads_callback(result):
+ """ Callback from core show threads """
+ threads = result.output
self.parse_threads(ast, threads)
+ return result
- if len(self.astThreads) > 0:
- """ All the pre-test cares about is that we saw threads, not what they are """
- super(ThreadPreTestCondition, self).passCheck()
- else:
- super(ThreadPreTestCondition, self).failCheck("No threads found")
+ def __threads_gathered(result):
+ """ Check the results once all threads are gathered """
+ if len(self.astThreads) > 0:
+ # All the pre-test cares about is that we saw threads, not what they are
+ super(ThreadPreTestCondition, self).passCheck()
+ else:
+ super(ThreadPreTestCondition, self).failCheck("No threads found")
+ self.__finished_deferred.callback(self)
+ return result
+ self.__finished_deferred = defer.Deferred()
+ defer.DeferredList([ast.cli_exec("core show threads").addCallback(__show_threads_callback)
+ for ast in self.ast]).addCallback(__threads_gathered)
+ return self.__finished_deferred
class ThreadPostTestCondition(ThreadTestCondition):
"""
@@ -105,58 +117,67 @@
super(ThreadPostTestCondition, self).__init__(test_config)
def evaluate(self, related_test_condition = None):
+ """ Override of TestCondition:evaluate """
- def evaluateThreadObjInList(threadObj, threadList):
+ def __evaluate_thread_obj_in_list(threadObj, threadList):
""" Local callback that determines if two thread entries are equal """
for obj in threadList:
+ # Ignore any remote connections - they may be us
if (threadObj[1] == 'netconsole'):
- """
- Some AMI connections, even after being disconnected, show up in core show threads. Ignore
- netconsole threads for now.
- """
return True
if (threadObj[0] == obj[0] and threadObj[1] == obj[1]):
return True
return False
- """ This must have a related_test_condition value passed in """
+ def __show_threads_callback(result):
+ """ Callback from core show threads """
+ threads = result.output
+ self.parse_threads(ast, threads)
+ return result
+
+ def __threads_gathered(result):
+ """ Called after all core show threads are finished """
+ if not self.astThreads:
+ # No threads found
+ super(ThreadPostTestCondition, self).failCheck("No threads found")
+ self.__finished_deferred.callback(self)
+ return result
+
+ for ast in self.astThreads:
+ # Make sure that for every instance of Asterisk we check in the post-test,
+ # an equivalent instance of Asterisk was checked in the pre-test
[... 71 lines stripped ...]
More information about the asterisk-commits
mailing list