[asterisk-commits] mjordan: testsuite/asterisk/trunk r4157 - in /asterisk/trunk: lib/python/aste...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Sep 11 09:19:43 CDT 2013
Author: mjordan
Date: Wed Sep 11 09:19:36 2013
New Revision: 4157
URL: http://svnview.digium.com/svn/testsuite?view=rev&rev=4157
Log:
Update simple_bridge test for Asterisk 12; simplify CEL parsing/checking
This patch does a few things.
1) It updates the simple_bridge test for Asterisk 12, such that it handles the
correct AMI events, CDR entries, and CEL events.
2) It adds a tool (and I emphasize it as a tool to aid in development) that
will snoop CEL AMI events and dump them out in YAML. I found this to be
helpful when producing the expected CEL events for this test; it may help
others as well.
3) It updates and simplifies the CEL parsing. See the lengthy explanation on
the peer review for more information.
Review: https://reviewboard.asterisk.org/r/2799/
(closes issue ASTERISK-22323)
Reported by: mjordan
Modified:
asterisk/trunk/lib/python/asterisk/ami.py
asterisk/trunk/lib/python/asterisk/cel.py
asterisk/trunk/tests/bridge/simple_bridge/test-config.yaml
Modified: asterisk/trunk/lib/python/asterisk/ami.py
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/lib/python/asterisk/ami.py?view=diff&rev=4157&r1=4156&r2=4157
==============================================================================
--- asterisk/trunk/lib/python/asterisk/ami.py (original)
+++ asterisk/trunk/lib/python/asterisk/ami.py Wed Sep 11 09:19:36 2013
@@ -266,6 +266,42 @@
self.test_object.set_passed(self.passed)
return callback_param
+
+class CelRequirement(object):
+ '''
+ A particular set of requirements that should be matched on for CEL
+ event checking
+ '''
+
+ def __init__(self, requirements):
+ ''' Constructor '''
+
+ # Make everything case insensitive for sanity
+ self.requirements = {}
+ for key, value in requirements['match'].items():
+ lower_key = key.lower()
+ self.requirements[lower_key] = value
+ self.orderings = requirements.get('partialorder') or []
+ self.named_id = requirements.get('id')
+
+ def is_match(self, event):
+ ''' Determine if this event matches us '''
+
+ for key, value in event.items():
+ item = self.requirements.get(key)
+ if item is None:
+ continue
+ if re.match(item, value) is None:
+ logger.debug('Skipping %s - %s does not equal %s for field %s' %
+ (event['eventname'], item, value, key))
+ return False
+ logger.debug('Matched CEL event %s' % event['eventname'])
+ return True
+
+ def __str__(self):
+ return str(self.requirements)
+
+
class AMICel(AMIEventInstance):
'''
A subclass of AMIEventInstance that operates by matching headers of
@@ -274,381 +310,98 @@
checking CEL events and that a partial order may be specified to allow some
events to be out of order.
'''
+
+ # Class level list of all instances of this class
+ ami_cel_instances = []
+
+ # All matched expected events that have an ordering
+ matched_cel_events = []
+
+ # All unmatched expected events that have an ordering
+ unmatched_cel_events = []
+
def __init__(self, instance_config, test_object):
+ ''' Constructor '''
super(AMICel, self).__init__(instance_config, test_object)
- self.match_index = 0
- self.submatch_index = None
- self.cel_ids = []
+
self.match_requirements = []
- self.partial_order_requirements = []
- self.cel_eventnames = []
- self.matched_events = []
- self.marked_failed = False
-
+ self.test_object.register_stop_observer(self._stop_callback)
+
+ # Creat our requirements
for instance in instance_config['requirements']:
- if 'id' not in instance:
- logger.error("No 'id' keyword was found for a cel requirement "
- "in the test's yaml file.")
- raise Exception
-
- if not instance['id']:
- logger.error("No value found for the 'id' keyword of a cel "
- "requirement in the test's yaml file.")
- raise Exception
-
- if instance['id'] in self.cel_ids:
- logger.error("The cel id '%s' is a duplicate. ID's must be "
- "unique." % instance['id'])
- raise Exception
-
- self.cel_ids.append(instance['id'])
-
- self.match_requirements.append(
- instance.get('match', {}))
-
- if 'partialorder' not in instance:
- self.partial_order_requirements.append(
- instance.get('partialorder',
- {'after' : None, 'before' : None}))
- else:
- tmp = {}
- origpartorder = instance['partialorder']
- for k,v in origpartorder.items():
- # Don't change an int of 0 to None. This allows it to be
- # caught in the regex later in case the single quotes were
- # forgotten in the config.
- if not v and v != 0 and v is not None:
- tmp[k] = None
- else:
- tmp[k] = v
-
- if 'after' not in tmp:
- tmp['after'] = None
- if 'before' not in tmp:
- tmp['before'] = None
- self.partial_order_requirements.append(tmp)
-
- self.__verify_match_requirements(self.match_requirements)
-
- # Remove any duplicates from our list of CEL EventName's
- self.cel_eventnames = list(set(self.cel_eventnames))
-
- def __verify_match_requirements(self, match_requirements):
- cel_cnt = 0
-
- for item in range(0, len(match_requirements)):
- # Fixup empty strings defined in the test's yaml file.
- for k, v in match_requirements[item].items():
- if not v:
- logger.debug("No expected header for '%s', using '^$'" % k)
- match_requirements[item][k] = '^$'
- # Build list of CEL EventName's from test's yaml file. Used later on to
- # ignore any received event where the EventName is not found in this list.
- if "EventName" not in match_requirements[item]:
- logger.error("No EventName specified. Aborting test.")
- raise Exception
- eventname = match_requirements[item].get('EventName')
- if eventname is None:
- logger.error("No value found for 'EventName' or it's not "
- "defined in the test's yaml file. Aborting test.")
- raise Exception
-
- self.cel_eventnames.append(eventname)
-
- # Check if 'after' is found in the test's yaml file for this event
- # requirement and if it's a string of one or more digits.
- after = self.partial_order_requirements[item].get('after')
- if after is not None:
- try:
- if not re.match('^[a-zA-Z0-9_-]*$', after):
- logger.error("CEL ID '%s': The value of 'after' must "
- "be a string. Aborting test." %
- self.cel_ids[cel_cnt])
- raise Exception
- except TypeError:
- logger.error("CEL ID '%s': The value of 'after' must be a "
- "string. Aborting test." %
- self.cel_ids[cel_cnt])
- raise Exception
-
- # Check if 'before' is found in the test's yaml file for this event
- # requirement and if it's a string of one or more digits.
- before = self.partial_order_requirements[item].get('before')
- if before is not None:
- try:
- if not re.match('^[a-zA-Z0-9_-]*$', before):
- logger.error("CEL id '%s': The value of 'before' must "
- "be a string. Aborting test." %
- self.cel_ids[cel_cnt])
- raise Exception
- except TypeError:
- logger.error("CEL ID '%s': The value of 'before' must be "
- "a string. Aborting test." %
- self.cel_ids[cel_cnt])
- raise Exception
-
- # Get dict from list for whatever index we are on:
- d = match_requirements[item]
-
- # Convert the dict keys to lowercase but leave the values as is for our
- # expected event.
- tmp = [(k.lower(),v) for k,v in d.items()]
- match_requirements.append(dict(tmp))
- cel_cnt += 1
-
- # Remove the orignal items leaving only those whose keys are now lower
- # case
- for x in range(0, cel_cnt):
- match_requirements.pop(0)
-
- return match_requirements
+ self.match_requirements.append(CelRequirement(instance))
+
+ # Add of all our named events to the lists of events that haven't
+ # occurred yet
+ named_events = [ev for ev in self.match_requirements if
+ ev.named_id is not None]
+ AMICel.unmatched_cel_events.extend(named_events)
+
+ AMICel.ami_cel_instances.append(self)
def event_callback(self, ami, event):
- # Ignore any received CEL events where the EventName is not a
- # requirement listed in the test's yaml.
- eventname = event.get('eventname')
- if eventname not in self.cel_eventnames:
- logger.debug("Ignoring CEL EventName '%s'" % eventname)
+ ''' Callback called by the base class when an event matches '''
+
+ if len(self.match_requirements) == 0:
return
- # Check if we already made a match for this expected event. If so then
- # skip it.
- for m in range(self.match_index, len(self.match_requirements)):
- if self.cel_ids[self.match_index] in self.matched_events:
- logger.info("Skipping requirement ID '%s' since we already "
- "matched it." % self.cel_ids[self.match_index])
- self.match_index += 1
-
- logger.info("Expecting requirement ID '%s'" %
- self.cel_ids[self.match_index])
- # Get dict from list for whatever index we are on:
- expected = self.match_requirements[self.match_index]
-
- for k,v in expected.items():
- if self.marked_failed: return
- if k not in event.keys():
- self.mark_failed('nokey', self.cel_ids[self.match_index], k, event)
- return
- if not re.match(v, event.get(k)):
- match_found = False
- submatch_found = False
- logger.debug("A requirement 'match' was NOT met against "
- "requirement ID '%s'" % self.cel_ids[self.match_index])
- # Check partial order to see if being out of order is allowed
- self.check_partorder_exists(self.match_index, event,
- match_found)
- if self.marked_failed: return
- # See if this received event matches any other requirements.
- submatch_found = self.find_requirement_match(event)
- if self.marked_failed: return
- # Now lets see if this requirement has a partial order specified
- self.check_partorder_exists(self.submatch_index, event,
- match_found, submatch_found)
- else:
- match_found = True
- logger.debug("A requirement 'match' was met against "
- "requirement ID '%s'" % self.cel_ids[self.match_index])
- self.check_partorder_exists(self.match_index, event,
- match_found)
-
- if self.submatch_index is not None:
- logger.info("All criteria has been met for requirement ID '%s'" %
- self.cel_ids[self.submatch_index])
- self.matched_events.append(self.cel_ids[self.submatch_index])
- self.submatch_index = None
- # Not incrementing self.match_index here since we're still
- # expecting the requirement that we haven't successfully matched to
- else:
- logger.info("All criteria has been met for requirement ID '%s'" %
- self.cel_ids[self.match_index])
- self.matched_events.append(self.cel_ids[self.match_index])
- # Increment so we expect a new requirement since we matched the
- # one we were on.
- self.match_index += 1
-
- logger.debug("Matched requirements so far: %s" % self.matched_events)
- return (ami, event)
-
- def check_partorder_exists(self, index, event, match_found,
- submatch_found = None):
- after = self.partial_order_requirements[index].get('after')
- before = self.partial_order_requirements[index].get('before')
- # If a before/after partial order isn't defined for this expected event
- # then we must fail it as the expected event did not match the
- # received event.
- logger.debug("Checking if partial order exists on requirement ID "
- "'%s'" % self.cel_ids[index])
-
- if match_found:
- # if no order specified then we want this to pass
- if after is None and before is None:
- return
- else:
- logger.debug("Partial order found on requirement ID '%s'. "
- "Strict ordering NOT enforced." %
- self.cel_ids[index])
- # check before and after order
- self.check_order(index, event, match_found)
- return
- if not match_found and not submatch_found:
- if after is None and before is None:
- logger.debug("No partial order found on requirement ID "
- "'%s'. Strict ordering enforced." %
- self.cel_ids[index])
- self.mark_failed('partial_order', self.cel_ids[index], event)
- return
- else:
- logger.debug("Found partial order on requirement ID '%s'. "
- "Strict ordering NOT enforce for this expected event." %
- self.cel_ids[index])
- return
- if not match_found and submatch_found:
- if after is None and before is None:
- logger.debug("No partial order found on requirement ID "
- "'%s'. Strict ordering enforced on this sub match." %
- self.cel_ids[index])
- self.mark_failed('partial_order', self.cel_ids[index], event)
- return
- else:
- logger.debug("Found partial order on requirement ID '%s'. "
- "Strict ordering NOT enforce for this expected event "
- "sub match." % self.cel_ids[index])
- # check before and after order
- self.check_order(index, event, match_found)
- return
-
- def find_requirement_match(self, event):
- logger.debug("Trying to find a requirement that matches")
- submatch_found = False
- # Search from our current index+1(since we know it doesn't match our
- # current index) to the last
- for i in range(self.match_index + 1, len(self.match_requirements)):
- # Get dict from list for whatever index we are on:
- expected = self.match_requirements[i]
-
- hdrmatchcnt = 0
- numkeys = 0
- for k,v in expected.items():
- numkeys += 1
- if re.match(v, event.get(k)):
- hdrmatchcnt += 1
- if hdrmatchcnt == numkeys:
- self.submatch_index = i
- submatch_found = True
- break
-
- if submatch_found:
- logger.debug("Found a sub requirement that matches at ID '%s'" %
- self.cel_ids[self.submatch_index])
- else:
- self.mark_failed('nomatches', None, None, event)
-
- return submatch_found
-
- def check_order(self, index, event, match_found):
- # Check if the 'after' partial order requirement is met.
- matched_after = self.check_after_order(index)
-
- # Check if the 'before' partial order requirement is met.
- matched_before = self.check_before_order(index)
-
- if not matched_after or not matched_before:
- if match_found:
- logger.debug("A match was found at requirement ID '%s' "
- "but the partial order requirement failed!" %
- self.cel_ids[index])
- else:
- logger.debug("A match was found at sub requirement ID "
- "'%s' but the partial order requirement failed!" %
- self.cel_ids[index])
- logger.warning("Received event does *NOT* match expected "
- "event")
- self.mark_failed('partial_order', self.cel_ids[index])
-
- def check_after_order(self, index):
- # Lets see if we have a 'after' partial order specified for this
- # expected event we found to match the received event.
- logger.debug("Checking the 'after' partial order requirements for expected "
- "event at requirement ID '%s'" % self.cel_ids[index])
- # We know that either 'after' or 'before' has a value since
- # check_partorder_exists() already told us that at least one of them does.
- # If 'after' is None then it's NOT a problem and therefore we set our
- # var to True.
- if self.partial_order_requirements[index].get('after') is None:
- after_range_matched = True
- else:
- after = self.partial_order_requirements[index].get('after')
- # Check the 'after' order specified on the expected event that was
- # matched to see if the expected event corresponding to the value of
- # 'after' was already matched or not.
- if after in self.matched_events:
- logger.debug("The expected match for requirement ID '%s' did "
- "occur after the requirement ID '%s'" %
- (self.cel_ids[index], after))
- after_range_matched = True
- else:
- logger.debug("The expected match for requirement ID '%s' did "
- "*NOT* occur after the requirement ID '%s'" %
- (self.cel_ids[index], after))
- after_range_matched = False
-
- return after_range_matched
-
- def check_before_order(self, index):
- logger.debug("Checking the 'before' partial order requirements for expected "
- "event at requirement ID '%s'" % self.cel_ids[index])
- # We know that either 'after' or 'before' has a value since
- # check_partorder_exists() already told us that at least one of them does.
- # If 'before' is None then it's NOT a problem and therefore we set our
- # var to True.
- if self.partial_order_requirements[index].get('before') is None:
- before_range_matched = True
- else:
- before = self.partial_order_requirements[index].get('before')
- # Check the 'before' order specified on the expected event that was
- # matched to see if the expected event corresponding to the value of
- # 'before' was already matched or not.
- if before not in self.matched_events:
- logger.debug("The expected match for requirement ID '%s' did "
- "occur before the requirement ID '%s'" %
- (self.cel_ids[index], before))
- before_range_matched = True
- else:
- logger.debug("The expected match for requirement ID '%s' did "
- "*NOT* occur before the requirement ID '%s'" %
- (self.cel_ids[index], before))
- before_range_matched = False
-
- return before_range_matched
-
- def mark_failed(self, item_failed, cel_id, expected = None, received = None):
- self.passed = False
- self.marked_failed = True
- if item_failed == "partial_order":
- logger.error("The partial order failed or doesn't exist for "
- "requirement ID '%s'" % cel_id)
- if item_failed == "match":
- logger.error("The match failed for requirement ID '%s'" % cel_id)
- logger.error("=== Event expected ===")
- logger.error(expected)
- logger.error("=== Event received ===")
- logger.error(received)
- if item_failed == "nomatches":
- logger.error("No requirement could be matched for the received "
- "event:")
- logger.error("%s" % received)
- if item_failed == "nokey":
- logger.error("Required CEL key '%s' not found in received "
- "event" % expected)
- logger.error("=== Event received ===")
- logger.error(received)
-
- logger.debug("Marking test as failed!")
- return
-
- def check_result(self, callback_param):
- self.test_object.set_passed(self.passed)
- return callback_param
+ logger.debug('Received CEL event %s' % str(event))
+
+ req = self.match_requirements[0]
+ if not req.is_match(event):
+ logger.debug('Dropping event %s - next required event is %s' %
+ (event['eventname'], req.requirements['eventname']))
+ return
+
+ self.match_requirements.pop(0)
+
+ if len(req.orderings) > 0:
+ self._check_orderings(req)
+
+ if req.named_id is not None:
+ AMICel.unmatched_cel_events.remove(req)
+ AMICel.matched_cel_events.append(req)
+
+ def _stop_callback(self, reason):
+ ''' Stop observer on the test_object. Called when Asterisk has stopped
+ at the end of the test '''
+
+ if len(self.match_requirements) != 0:
+ logger.warning('Length of expected CEL requirements not zero: %d' %
+ len(self.match_requirements))
+ logger.warning('Missed CEL requirement: %s' %
+ str(self.match_requirements[0]))
+ self.test_object.set_passed(False)
+ return reason
+
+ logger.info('All expected CEL requirements matched')
+ self.test_object.set_passed(True)
+ return reason
+
+ def _check_orderings(self, cel_requirement):
+ ''' Check that this matched CelRequirement occurred in the right
+ order '''
+
+ for order_type, named_event in cel_requirement.orderings.items():
+ order_type = order_type.lower()
+ if order_type == 'after':
+ matches = [ev for ev in AMICel.matched_cel_events if
+ ev.named_id == named_event]
+ if len(matches) == 0:
+ logger.warning('Event %s did not occur after %s; failing' %
+ (str(cel_requirement), named_event))
+ self.test_object.set_passed(False)
+ elif order_type == 'before':
+ matches = [ev for ev in AMICel.unmatched_cel_events if
+ ev.named_id == named_event]
+ if len(matches) == 0:
+ logger.warning('Event %s did not occur before %s; failing' %
+ (str(cel_requirement), named_event))
+ self.test_object.set_passed(False)
+ else:
+ logger.warning('Unknown partialorder type %s; ignoring' %
+ order_type)
+
class AMICallbackInstance(AMIEventInstance):
'''
Modified: asterisk/trunk/lib/python/asterisk/cel.py
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/lib/python/asterisk/cel.py?view=diff&rev=4157&r1=4156&r2=4157
==============================================================================
--- asterisk/trunk/lib/python/asterisk/cel.py (original)
+++ asterisk/trunk/lib/python/asterisk/cel.py Wed Sep 11 09:19:36 2013
@@ -10,6 +10,7 @@
the GNU General Public License Version 2.
"""
+import yaml
import unittest
import sys
import csv
@@ -19,6 +20,57 @@
import time
LOGGER = logging.getLogger(__name__)
+
+
+class CELSniffer(object):
+ '''
+ A pluggable module that sniffs AMI CEL events and dumps them into a YAML
+ file. Useful during test writing to create a baseline of expected CEL events
+ '''
+
+ def __init__(self, module_config, test_object):
+ ''' Constructor '''
+ test_object.register_ami_observer(self.ami_connect)
+ test_object.register_stop_observer(self.stop_handler)
+ self.events = []
+ if module_config is None:
+ self.filters = {}
+ self.display = []
+ else:
+ self.filters = module_config.get('filters') or {}
+ self.display = module_config.get('display') or []
+
+ def ami_connect(self, ami):
+ ''' AMI connection handler '''
+ ami.registerEvent('CEL', self.cel_handler)
+
+ def cel_handler(self, ami, event):
+ ''' Handle a CEL event '''
+ for filter_key, filter_value in self.filters.items():
+ if re.match(filter_value, event.get(filter_key.lower())) is None:
+ return
+ self.events.append(event)
+
+ def stop_handler(self, reason):
+ ''' Write out the file. Currently hard codd to cel_events.yaml '''
+ stream = file('cel_events.yaml', 'w')
+ if len(self.display) == 0:
+ yaml.dump(self.events, stream)
+ else:
+ items = []
+ for ev_item in self.events:
+ item = {}
+ for key in self.display:
+ key = key.lower()
+ if key not in ev_item:
+ continue
+ item[key] = ev_item[key]
+ items.append(item)
+ yaml.dump(items, stream)
+ stream.close()
+
+ return reason
+
class CELModule(object):
''' A module that checks a test for expected CEL results '''
Modified: asterisk/trunk/tests/bridge/simple_bridge/test-config.yaml
URL: http://svnview.digium.com/svn/testsuite/asterisk/trunk/tests/bridge/simple_bridge/test-config.yaml?view=diff&rev=4157&r1=4156&r2=4157
==============================================================================
--- asterisk/trunk/tests/bridge/simple_bridge/test-config.yaml (original)
+++ asterisk/trunk/tests/bridge/simple_bridge/test-config.yaml Wed Sep 11 09:19:36 2013
@@ -13,16 +13,17 @@
config-section: 'cdr-config'
typename: 'cdr.CDRModule'
-
+ maxversion: '12.0.0'
+ config-section: 'ami-uut-v11'
+ typename: 'ami.AMIEventModule'
+ -
+ minversion: '12.0.0'
config-section: 'cel-config'
- typename: 'cel.CELModule'
+ typename: 'ami.AMIEventModule'
-
+ minversion: '12.0.0'
+ config-section: 'ami-uut-v12'
typename: 'ami.AMIEventModule'
- config-section: 'ami-uut-v12'
- minversion: '12.0.0'
- -
- typename: 'ami.AMIEventModule'
- config-section: 'ami-uut-v11'
- maxversion: '12.0.0'
bridge-config:
test-runs:
@@ -42,7 +43,8 @@
Event: 'BridgeCreate'
requirements:
match:
- BridgeType: 'simple_bridge'
+ BridgeType: 'basic'
+ BridgeTechnology: 'simple_bridge'
count: '2'
-
type: 'headermatch'
@@ -54,7 +56,8 @@
requirements:
match:
BridgeUniqueid: '.*-.*-.*'
- BridgeType: 'simple_bridge'
+ BridgeType: 'basic'
+ BridgeTechnology: 'simple_bridge'
ChannelState: '6'
ChannelStateDesc: 'Up'
CallerIDNum: '1234'
@@ -76,7 +79,8 @@
requirements:
match:
BridgeUniqueid: '.*-.*-.*'
- BridgeType: 'simple_bridge'
+ BridgeType: 'basic'
+ BridgeTechnology: 'simple_bridge'
ChannelState: '6'
ChannelStateDesc: 'Up'
ConnectedLineNum: '1234'
@@ -97,7 +101,8 @@
requirements:
match:
BridgeUniqueid: '.*-.*-.*'
- BridgeType: 'simple_bridge'
+ BridgeType: 'basic'
+ BridgeTechnology: 'simple_bridge'
ChannelState: '6'
ChannelStateDesc: 'Up'
CallerIDNum: '1234'
@@ -119,7 +124,8 @@
requirements:
match:
BridgeUniqueid: '.*-.*-.*'
- BridgeType: 'simple_bridge'
+ BridgeType: 'basic'
+ BridgeTechnology: 'simple_bridge'
ChannelState: '6'
ChannelStateDesc: 'Up'
ConnectedLineNum: '1234'
@@ -139,7 +145,8 @@
requirements:
match:
BridgeUniqueid: '.*-.*-.*'
- BridgeType: 'simple_bridge'
+ BridgeType: 'basic'
+ BridgeTechnology: 'simple_bridge'
count: '2'
ami-uut-v11:
@@ -229,221 +236,136 @@
cel-config:
-
- file: 'Master'
- lines:
- -
- eventtype: 'CHAN_START'
- cidname: 'Alice'
- cidnum: '1234'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- -
- eventtype: 'APP_START'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- app: 'Dial'
- -
- eventtype: 'CHAN_START'
- cidname: 'Bob'
- cidnum: '4321'
- channel: '.*/bob-.*'
- -
- eventtype: 'ANSWER'
- cidname: 'Bob'
- cidnum: '4321'
- channel: '.*/bob-.*'
- app: 'AppDial'
- appdata: '\(Outgoing Line\)'
- -
- eventtype: 'ANSWER'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- app: 'Dial'
- -
- eventtype: 'BRIDGE_START'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- app: 'Dial'
- bridgepeer: '.*/bob-.*'
- -
- eventtype: 'BRIDGE_END'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- app: 'Dial'
- bridgepeer: '.*/bob-.*'
- -
- eventtype: 'HANGUP'
- cidname: 'Bob'
- cidnum: '4321'
- channel: '.*/bob-.*'
- app: 'AppDial'
- appdata: '\(Outgoing Line\)'
- eventextra: '16,.*/alice-.*'
- -
- eventtype: 'CHAN_END'
- cidname: 'Bob'
- cidnum: '4321'
- channel: '.*/bob-.*'
- app: 'AppDial'
- appdata: '\(Outgoing Line\)'
- -
- eventtype: 'APP_END'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- app: 'Dial'
- -
- eventtype: 'HANGUP'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- eventextra: '16,.*/alice-.*,ANSWER'
- -
- eventtype: 'CHAN_END'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- -
- eventtype: 'LINKEDID_END'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- -
- eventtype: 'CHAN_START'
- cidname: 'Alice'
- cidnum: '1234'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- -
- eventtype: 'APP_START'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- app: 'Dial'
- -
- eventtype: 'CHAN_START'
- cidname: 'Bob'
- cidnum: '4321'
- channel: '.*/bob-.*'
- -
- eventtype: 'ANSWER'
- cidname: 'Bob'
- cidnum: '4321'
- channel: '.*/bob-.*'
- app: 'AppDial'
- appdata: '\(Outgoing Line\)'
- -
- eventtype: 'ANSWER'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- app: 'Dial'
- -
- eventtype: 'BRIDGE_START'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- app: 'Dial'
- bridgepeer: '.*/bob-.*'
- -
- eventtype: 'BRIDGE_END'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- app: 'Dial'
- bridgepeer: '.*/bob-.*'
- -
- eventtype: 'HANGUP'
- cidname: 'Bob'
- cidnum: '4321'
- channel: '.*/bob-.*'
- app: 'AppDial'
- appdata: '\(Outgoing Line\)'
- eventextra: '16,.*/bob-.*'
- -
- eventtype: 'CHAN_END'
- cidname: 'Bob'
- cidnum: '4321'
- channel: '.*/bob-.*'
- app: 'AppDial'
- appdata: '\(Outgoing Line\)'
- -
- eventtype: 'APP_END'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- app: 'Dial'
- -
- eventtype: 'HANGUP'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- eventextra: '16,.*/bob-.*,ANSWER'
- -
- eventtype: 'CHAN_END'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
- -
- eventtype: 'LINKEDID_END'
- cidname: 'Alice'
- cidnum: '1234'
- dnid: 'test_call'
- exten: 'test_call'
- context: 'default'
- channel: '.*/alice-.*'
-
+ type: 'cel'
+ conditions:
+ match:
+ Channel: '.*/bob-.*'
+ requirements:
+ # First iteration
+ -
+ id: 'bob-start-one'
+ partialorder:
+ after: 'alice-app-start-one'
+ match:
+ EventName: 'CHAN_START'
+ -
+ id: 'bob-answer-one'
+ partialorder:
+ before: 'alice-answer-one'
+ before: 'alice-enter-bridge-one'
+ match:
+ EventName: 'ANSWER'
+ -
+ id: 'bob-enter-bridge-one'
+ match:
+ EventName: 'BRIDGE_ENTER'
+ -
+ match:
+ EventName: 'BRIDGE_EXIT'
+ -
+ match:
+ EventName: 'HANGUP'
+ -
+ match:
+ EventName: 'CHAN_END'
+ # Second iteration
+ -
+ id: 'bob-start-two'
+ partialorder:
+ after: 'alice-app-start-two'
+ match:
+ EventName: 'CHAN_START'
+ -
+ id: 'bob-answer-two'
+ partialorder:
+ before: 'alice-answer-two'
+ before: 'alice-bridge-enter-two'
+ match:
+ EventName: 'ANSWER'
+ -
+ match:
+ EventName: 'BRIDGE_ENTER'
+ -
+ match:
+ EventName: 'BRIDGE_EXIT'
+ -
+ match:
+ EventName: 'HANGUP'
+ -
+ id: 'bob-end-two'
+ match:
+ EventName: 'CHAN_END'
+ -
+ type: 'cel'
+ conditions:
+ match:
+ Channel: '.*/alice-.*'
+ requirements:
+ # First iteration
+ -
+ match:
+ EventName: 'CHAN_START'
+ -
+ id: 'alice-app-start-one'
+ match:
+ EventName: 'APP_START'
+ -
+ id: 'alice-answer-one'
+ partialorder:
+ after: 'bob-answer-one'
+ before: 'bob-enter-bridge-one'
+ match:
+ EventName: 'ANSWER'
+ -
+ id: 'alice-enter-bridge-one'
+ match:
+ EventName: 'BRIDGE_ENTER'
+ -
+ match:
+ EventName: 'BRIDGE_EXIT'
+ -
+ match:
[... 45 lines stripped ...]
More information about the asterisk-commits
mailing list