示例#1
0
    def decorator(subscriber: Callable) -> Callable:
        nonlocal source
        nonlocal identifier
        nonlocal constraints

        if identifier is None:
            identifier = source.__name__

        if identifier == 'constraints':
            errmsg = "Invalid identifier.  The word 'constraints' is reseved for delivering dynamic constraints."
            raise AKitSemanticError(errmsg) from None

        life_span = ResourceLifespan.Test

        source_info = resource_registry.lookup_resource_source(source)

        if constraints is not None and 'constraints' not in source_info.source_signature.parameters:
            raise AKitSemanticError(
                "Attempting to pass constraints to a parameter origin with no 'constraints' parameter."
            ) from None

        assigned_scope = "{}#{}".format(subscriber.__module__,
                                        subscriber.__name__)

        param_origin = ParameterOrigin(assigned_scope, identifier, source_info,
                                       life_span, constraints)
        resource_registry.register_parameter_origin(identifier, param_origin)

        return subscriber
示例#2
0
    def release_write(self):
        """
            Method called by a thread to release write access on the :class:`ReadWriteLock`.
        """
        tid = threading.get_ident()

        self._lock.acquire()
        try:
            if self._writer != tid:
                raise AKitSemanticError(
                    "Thread id(%d) attempting to release write lock when it was not owned."
                    % tid) from None

            if self._read_write_pivot >= 0:
                raise AKitSemanticError(
                    "Thread id(%d) is attempting to release the ReadWriteLock when it is in a read or neutral state."
                    % tid) from None

            self._read_write_pivot += 1

            # Make the decision to allow readers before we let any waiting writers change
            # the count of self._writers_waiting
            if self._writers_waiting == 0:
                self._read_gate.set()

            # Don't release the write gate until we have checked to see if another writer is waiting
            self._write_gate.release()
        finally:
            self._lock.release()

        return
示例#3
0
def lookup_test_root_type(test_root):

    test_root_module = os.path.join(test_root, os.path.join("__testroot__.py"))
    if not os.path.exists(test_root_module):
        errmsg = "The test root must have a module '__testroot__.py'. testroot={}".format(
            test_root_module)
        raise AKitSemanticError(errmsg) from None

    ROOT_TYPE = None

    trm_content = ""
    with open(test_root_module, 'r') as trmf:
        trm_content = trmf.read().strip()

    locals_vars = {}
    exec(trm_content, None, locals_vars)
    if "ROOT_TYPE" in locals_vars:
        ROOT_TYPE = locals_vars["ROOT_TYPE"]

    if ROOT_TYPE is None:
        errmsg = "The test root module must have a 'ROOT_TYPE' variable specifying (testplus, unittest).".format(
            test_root_module)
        raise AKitSemanticError(errmsg) from None

    if not ((ROOT_TYPE == TestRootType.TESTPLUS) or
            (ROOT_TYPE == TestRootType.UNITTEST)):
        errmsg = "Unknow test root type {}".format(ROOT_TYPE)
        raise AKitSemanticError(errmsg) from None

    return ROOT_TYPE
示例#4
0
    def activate_integration_point(self, role: str, coordinator_constructor: callable):
        """
            This method should be called from the attach_to_environment methods from individual couplings
            in order to register the base level integrations.  Integrations can be hierarchical so it
            is only necessary to register the root level integration couplings, the descendant couplings can
            be called from the root level couplings.

            :param role: The name of a role to assign for a coupling.
            :param coupling: The coupling to register for the associated role.
        """

        if role.startswith("coordinator/"):
            
            if "coordinator/serial" not in self._integration_points_activated:
                self._integration_points_activated["coordinator/serial"] = True

            if "coordinator/power" not in self._integration_points_activated:
                self._integration_points_activated["coordinator/power"] = True

            _, coord_type = role.split("/")
            if coord_type == "upnp" or coord_type == "ssh":
                if role not in self._integration_points_activated:
                    self._integration_points_activated[role] = coordinator_constructor
                else:
                    raise AKitSemanticError("Attempted to activate the UPNP coordinator twice.") from None
            else:
                raise AKitSemanticError("Unknown coordinator type '%s'." % role) from None
        else:
            raise AKitSemanticError("Don't know how to activate integration point of type '%s'." % role) from None

        return
示例#5
0
    def __init__(self,
                 patterns: List[Union[str, re.Pattern]],
                 *,
                 match_type: str = None,
                 destination: str = None,
                 required: bool = False,
                 repeats: bool = False,
                 strict: Optional[bool] = None,
                 consume: bool = False):

        if match_type is not None and destination is None:
            errmsg = "RegExPattern: If 'match_type' is specified then you must provide a 'destination' parameter."
            raise AKitSemanticError(errmsg)

        self.destination = destination
        self.patterns = None

        if len(self.patterns) == 0:
            errmsg = "The RegExMultiPattern object requires at least one pattern to be passed."
            raise AKitSemanticError(errmsg)
        else:
            self.patterns = [
                p if isinstance(p, re.Pattern) else re.compile(p)
                for p in patterns
            ]

        self.match_type = match_type
        self.required = required
        self.repeats = repeats
        self.strict = strict
        self.consume = consume
        return
示例#6
0
    def has_any_feature(self, feature_list: List[FeatureTag]):

        has_any = False

        if len(feature_list) == 0:
            errmsg = "has_all_features: 'feature_list' cannot be empty."
            raise AKitSemanticError(errmsg)

        first_item = feature_list[0]
        if isinstance(first_item, str):
            for feature in feature_list:
                fid = feature

                hasfeature = fid in self._feature_tags
                if hasfeature:
                    has_any = True
                    break
        elif issubclass(first_item, FeatureTag):
            for feature in feature_list:
                fid = feature.ID

                hasfeature = fid in self._feature_tags
                if hasfeature:
                    has_any = True
                    break
        else:
            errmsg = "The 'feature_list' parameter must contain items of type 'FeatureTag' or 'str'. item={}".format(
                repr(first_item)
            )
            raise AKitSemanticError(errmsg)

        return has_any
示例#7
0
    def __init__(self,
                 pattern: Union[str, re.Pattern],
                 *,
                 match_type: str = None,
                 destination: str = None,
                 required: bool = False,
                 repeats: bool = False,
                 strict: Optional[bool] = None,
                 consume: bool = False):

        if match_type is not None and destination is None:
            errmsg = "RegExPattern: If 'match_type' is specified then you must provide a 'destination' parameter."
            raise AKitSemanticError(errmsg)

        if repeats and match_type is None:
            errmsg = "RegExPattern: If 'repeats=True', you must specify an 'match_type' parameter."
            raise AKitSemanticError(errmsg)

        self.pattern = pattern
        if isinstance(pattern, str):
            self.pattern = re.compile(pattern)
        self.match_type = match_type
        self.destination = destination
        self.required = required
        self.repeats = repeats
        self.strict = strict
        self.consume = consume
        return
示例#8
0
    def aggregate_results(self) -> Tuple[Dict, Dict]:
        """
        """
        
        if not self._started:
            errmsg = "{}: You must call the 'begin' method to start the evolution and wait for the " \
                "evolution to complete before calling the 'aggregate_results' method."
            raise AKitSemanticError(errmsg)
        
        if not self._completed:
            errmsg = "{}: You must call the 'wait_for_completion' to wait for the " \
                "evolution to complete before calling the 'aggregate_results' method."
            raise AKitSemanticError(errmsg)

        rtn_results = {}
        rtn_exceptions = {}

        for pident, pfuture in self._procedure_futures.items():

            try:
                fresult = pfuture.result()
                rtn_results[pident] = fresult
            except (CancelledError, TimeoutError) as ferr:
                rtn_exceptions[pident] = ferr
            except:
                fexc = pfuture.exception()
                rtn_exceptions[pident] = fexc

        return rtn_results, rtn_exceptions
示例#9
0
def originate_parameter(source_func,
                        *,
                        identifier: Optional[None],
                        life_span: ResourceLifespan = None,
                        assigned_scope: Optional[str] = None,
                        constraints: Optional[Dict] = None):

    if source_func is None:
        errmsg = "The 'source_func' parameter cannot be 'None'."
        raise AKitSemanticError(errmsg) from None

    if life_span == ResourceLifespan.Test:
        errmsg = "The 'life_span' parameter cannot be 'ResourceLifespan.Test'."
        raise AKitSemanticError(errmsg) from None

    if identifier is None:
        identifier = source_func.__name__

    if identifier == 'constraints':
        errmsg = "Invalid identifier.  The word 'constraints' is reseved for delivering dynamic constraints."
        raise AKitSemanticError(errmsg) from None

    source_info = resource_registry.lookup_resource_source(source_func)
    if assigned_scope is not None:
        if isinstance(source_info, IntegrationSource):
            errmsg = "The 'assigned_scope' parameter should not be specified unless the source of the resource is of type 'scope' or 'resource'."
            raise AKitSemanticError(errmsg) from None

    if constraints is not None and 'constraints' not in source_info.source_signature.parameters:
        raise AKitSemanticError(
            "Attempting to pass constraints to a parameter origin with no 'constraints' parameter."
        ) from None

    caller_frame = inspect.stack()[1]
    calling_module = inspect.getmodule(caller_frame[0])

    if life_span is None:
        res_type = source_info.resource_type
        if issubclass(res_type, IntegrationCoupling):
            life_span = ResourceLifespan.Session
        else:
            life_span = ResourceLifespan.Package

    if life_span == ResourceLifespan.Package:
        if assigned_scope is None:
            assigned_scope = calling_module.__name__
    elif life_span == ResourceLifespan.Session:
        assigned_scope = "<session>"

    param_origin = ParameterOrigin(assigned_scope, identifier, source_info,
                                   life_span, constraints)
    resource_registry.register_parameter_origin(identifier, param_origin)

    return
示例#10
0
    def register_integration_point(self, role: str, coupling: BaseCoupling):
        """
            This method should be called from the attach_to_environment methods from individual couplings
            in order to register the base level integrations.  Integrations can be hierarchical so it
            is only necessary to register the root level integration couplings, the descendant couplings can
            be called from the root level couplings.

            :param role: The name of a role to assign for a coupling.
            :param coupling: The coupling to register for the associated role.
        """
        lscapeType = type(self)

        lscapeType.landscape_lock.acquire()
        try:
            if role not in self._integration_points_registered:
                self._ordered_roles.append(role)
                self._integration_points_registered[role] = coupling

                self._integration_point_registration_counter += 1
            else:
                raise AKitSemanticError(
                    "A coupling with the role %r was already registered." %
                    role) from None
        finally:
            lscapeType.landscape_lock.release()

        return
示例#11
0
    def add_descendent_parameter_origination(
            self, assigned_scope: str, parameter_origin: ParameterOrigin):
        """
            Adds a descendent parameter origin object into the parameter origin table of the
            assigned scope path provided.

            :param assigned_scope: The full scope name of the scope to assign the parameter
                                   origin to.
            :param parameter_origin: The parameter origin object that is being inserted into
                                     the parameter origin table of the assigned scope.
        """

        if self._package is not None:
            err_msg = "The 'add_descendent' API can only be called on the root package."
            raise AKitSemanticError(err_msg) from None

        if self._package is None and assigned_scope == "<session>":
            if parameter_origin is not None:
                identifier = parameter_origin.identifier
                self._parameter_originations[identifier] = parameter_origin
                self._parameter_originations.move_to_end(identifier, last=True)
        else:
            is_test_scope = False
            if assigned_scope.find("#") > -1:
                is_test_scope = True
                assigned_scope = assigned_scope.replace("#", ".")
            to_walk_list = assigned_scope.split(".")
            path_stack = []

            self._add_descendent_parameter_origination(parameter_origin,
                                                       to_walk_list,
                                                       path_stack,
                                                       is_test_scope)

        return
示例#12
0
    def extend_features(self, features_to_add: Union[List[FeatureTag], List[str]]):
        """
            Used by derived class and mixins to extend the feature tags associated with
            a feature attached object.
        """

        if len(features_to_add) > 0:
            first_item = features_to_add[0]
            if isinstance(first_item, str):
                # We insert the features into the list sorted so we can make finding
                # features faster.
                for ft in features_to_add:
                    bisect.insort(self._feature_tags, ft)
            elif issubclass(first_item, FeatureTag):
                # We insert the features into the list sorted so we can make finding
                # features faster.
                for ft in features_to_add:
                    bisect.insort(self._feature_tags, ft.ID)
            else:
                errmsg = "The 'features_to_add' parameter must contain items of type 'FeatureTag' or 'str'. item={}".format(
                    repr(first_item)
                )
                raise AKitSemanticError(errmsg)

        return
示例#13
0
    def establish_connectivity(
            cls,
            allow_missing_devices: bool = False) -> Tuple[List[str], dict]:
        """
            This API is called so the `IntegrationCoupling` can establish connectivity with any compute or storage
            resources.

            :returns: A tuple with a list of error messages for failed connections and dict of connectivity
                      reports for devices devices based on the coordinator.
        """

        ssh_device_list = cls.landscape.get_ssh_device_list()

        if len(ssh_device_list) == 0:
            raise AKitSemanticError(
                "We should have not been called if no SSH devices are available."
            )

        upnp_coord = cls.landscape._internal_get_upnp_coord()

        ssh_config_errors, matching_device_results, missing_device_results = cls.coordinator.attach_to_devices(
            ssh_device_list, upnp_coord=upnp_coord)

        ssh_scan_results = {
            "ssh": {
                "matching_devices": matching_device_results,
                "missing_devices": missing_device_results
            }
        }

        return (ssh_config_errors, ssh_scan_results)
示例#14
0
 def _populate_embedded_devices(self, factory, description):
     """
         This method is overloaded to prohibit the poplulation of embedded devices insided embedded devices.
     """
     # pylint: disable=no-self-use,unused-argument
     raise AKitSemanticError(
         "Embedded devices inside an embedded device is currently not supported."
     ) from None
示例#15
0
    def decorator(source_function: Callable) -> Callable:
        nonlocal constraints

        signature = inspect.signature(source_function)
        integration_context = signature.return_annotation

        resource_type = None

        if integration_context == inspect._empty:
            errmsg = "Parameters factories for 'integration' functions must have an annotated return type."
            raise AKitSemanticError(errmsg) from None
        else:
            if integration_context._name == "Generator":
                ra_yield_type, ra_send_type, ra_return_type = integration_context.__args__
                if ra_yield_type is not NoneType:
                    resource_type = ra_yield_type
                elif ra_return_type is not NoneType:
                    resource_type = ra_return_type
            elif issubclass(integration_context, IntegrationCoupling):
                raise AKitSemanticError(
                    "Your resource function is returning an integration instead of yielding one."
                ) from None
            else:
                raise AKitSemanticError(
                    "You must pass a IntegrationCoupling derived object."
                ) from None

        if resource_type is not None:

            if not issubclass(resource_type, IntegrationCoupling):
                raise AKitSemanticError(
                    "The 'integration' decorator can only be used on resources that inherit from the 'IntegrationCoupling'."
                ) from None

            isource = IntegrationSource(source_function, resource_type,
                                        constraints)
            resource_registry.register_integration_source(isource)
        else:
            errmsg_lines = [
                "Unable to determine the resource type of the function which the 'integration' decorator was applied too.",
                "FUNCTION: {}".format(signature)
            ]
            errmsg = os.linesep.join(errmsg_lines)
            raise AKitSemanticError(errmsg) from None

        return source_function
示例#16
0
    def wait_for_completion(self, timeout: Optional[float]=None):

        if not self._started:
            errmsg = "{}: You must call the 'begin' method to start the evolution before calling the 'wait_for_completion' method."
            raise AKitSemanticError(errmsg)
        
        self._completed_gate.wait(timeout=timeout)

        return
示例#17
0
 def _register_root_device(self, extkey, extcls, device_table):
     """
         Method that registers the extension class of a specific type of root device.
     """
     if extkey not in device_table:
         device_table[extkey] = extcls
     else:
         raise AKitSemanticError(
             "A root device extension with the key=%r was already registered. (%s)"
             % (extkey, extcls)) from None
     return
示例#18
0
    def establish_connectivity(
            cls,
            allow_missing_devices: bool = False,
            upnp_recording: bool = False,
            allow_unknown_devices: bool = False) -> Tuple[List[str], dict]:
        """
            This API is called so the `IntegrationCoupling` can establish connectivity with any compute or storage
            resources.

            :returns: A tuple with a list of error messages for failed connections and dict of connectivity
                      reports for devices devices based on the coordinator.
        """
        lscape = cls.landscape

        exclude_interfaces = ["lo"]
        networking_info = lscape.networking
        if networking_info is not None and "upnp" in networking_info:
            upnp_info = networking_info["upnp"]
            if "exclude_interfaces" in upnp_info:
                exclude_interfaces = upnp_info["exclude_interfaces"]

        upnp_hint_table = lscape.get_upnp_device_config_lookup_table()

        if len(upnp_hint_table) == 0:
            raise AKitSemanticError(
                "we should not have been called if the upnp device config had 0 devices."
            ) from None

        required_devices = None
        if not allow_missing_devices:
            required_devices = [usn for usn in upnp_hint_table.keys()]

        found_device_results, matching_device_results, missing_device_results = cls.coordinator.startup_scan(
            upnp_hint_table,
            watchlist=upnp_hint_table,
            required_devices=required_devices,
            exclude_interfaces=exclude_interfaces,
            upnp_recording=upnp_recording,
            allow_unknown_devices=allow_unknown_devices)

        conn_results = {
            "upnp": {
                "found": found_device_results,
                "matching": matching_device_results,
                "missing": missing_device_results
            }
        }

        conn_errors = []

        return (conn_errors, conn_results)
示例#19
0
    def _locked_checkout_device(self, device) -> Optional[LandscapeDevice]:

        rtn_device = None

        keyid = device.keyid
        if keyid not in self._device_pool:
            raise AKitSemanticError("A device is being checked out, that is not in the device pool.") from None

        rtn_device = self._device_pool[keyid]

        del self._device_pool[keyid]
        self._checked_out_devices[keyid] = rtn_device

        return rtn_device
示例#20
0
    def add_descendent(self, test_ref: TestRef):

        if self._package is not None:
            err_msg = "The 'add_descendent' API can only be called on the root package."
            raise AKitSemanticError(err_msg) from None

        testname = test_ref.test_name
        module_name, _ = testname.split("#")
        to_walk_list = module_name.split(".")
        path_stack = []

        self._add_descendent(test_ref, to_walk_list, path_stack)

        return
示例#21
0
    def decorator(source_function: Callable) -> Callable:
        nonlocal constraints

        signature = inspect.signature(source_function)
        resource_context = signature.return_annotation

        resource_type = None

        if resource_context == inspect._empty:
            errmsg = "Parameters factories or 'resource' functions must have an annotated return type."
            raise AKitSemanticError(errmsg) from None
        elif hasattr(resource_context,
                     "_name") and resource_context._name == "Generator":
            ra_yield_type, ra_send_type, ra_return_type = resource_context.__args__
            if ra_yield_type is not NoneType:
                resource_type = ra_yield_type
            elif ra_return_type is not NoneType:
                resource_type = ra_return_type
        elif issubclass(resource_context, IntegrationCoupling):
            resource_type = resource_context
        else:
            resource_type = resource_context

        if resource_type is not None:

            sref = ResourceSource(source_function, query_function,
                                  resource_type, constraints)
            resource_registry.register_resource_source(sref)
        else:
            errmsg_lines = [
                "Unable to determine the resource type of the function which the 'resource' decorator was applied too.",
                "FUNCTION: {}".format(signature)
            ]
            errmsg = os.linesep.join(errmsg_lines)
            raise AKitSemanticError(errmsg) from None

        return source_function
示例#22
0
    def release_read(self):
        """
            Method called by a thread to release read access on the :class:`ReadWriteLock`.
        """
        tid = threading.get_ident()

        self._lock.acquire()
        try:
            if tid not in self._readers:
                raise AKitSemanticError(
                    "Thread id(%d) attempting to release read lock when it was not owned."
                    % tid) from None

            if self._read_write_pivot <= 0:
                raise AKitSemanticError(
                    "Thread id(%d) is attempting to release the ReadWriteLock when it is in a write or neutral state."
                    % tid) from None

            self._read_write_pivot -= 1

        finally:
            self._lock.release()

        return
示例#23
0
    def has_feature(self, feature: Union[FeatureTag, str]):
        fid = None

        if isinstance(feature, str):
            fid = feature
        elif issubclass(feature, FeatureTag):
            fid = feature.ID
        else:
            errmsg = "The 'feature' parameter must be of type 'FeatureTag' or 'str'. item={}".format(
                repr(feature)
            )
            raise AKitSemanticError(errmsg)

        hasfeature = fid in self._feature_tags

        return hasfeature
示例#24
0
    def _ensure_activation(self):
        """
            Called by methods that require Landscape activation in order to make sure the 'activate' method
            has been called before the attempted use of the specified method.

            :param method: The name of the method guarding against the use of a Landscape that has not been
                           activated.
        """
        if self._operational_gate is not None:
            self._operational_gate.wait()
        else:
            curframe = inspect.currentframe()
            calframe = inspect.getouterframes(curframe, 2)
            guarded_method = calframe[1][3]

            errmsg = "The Landscape must be activated before calling the '%s' method." % guarded_method
            raise AKitSemanticError(errmsg) from None

        return
示例#25
0
    def register_monitor(self, monitor: ReportMonitor):
        """
        """
        monitor_name = "{}:{}".format(monitor.report_class,
                                      monitor.report_topic)

        self._lock.acquire()
        try:
            if monitor_name in self._monitor_table:
                errmsg = "A 'ReportMonitor' named '{}' has already been registered.".format(
                    monitor_name)
                raise AKitSemanticError(errmsg) from None

            self._monitor_table[monitor_name] = monitor

            corr_ip = monitor.correspondance_ip
            monitor.set_report_endpoint(corr_ip, self._port)
        finally:
            self._lock.release()

        return
示例#26
0
    def register_parameter_origin(self, identifier: str,
                                  origin: ParameterOrigin):
        """
            The :method:`register_parameter_origin` is used to register an alias as a wellknown parameter
            so that subscriber functions can consume the parameter as an input parameter.
        """

        originating_scope = origin.originating_scope

        if self._scope_tree_root.has_descendent_parameter(
                originating_scope, identifier):
            errmsg = "A wellknown variable identified as '{}' has already been assigned to scope '{}'.".format(
                identifier, originating_scope)
            raise AKitSemanticError(errmsg) from None

        # Add the parameter origin to the identifiers_for_scope table for this scope so we
        # can lookup identifiers by scope
        self._scope_tree_root.add_descendent_parameter_origination(
            originating_scope, origin)

        return
示例#27
0
    def checkin_device(self, device: LandscapeDevice):
        """
            Returns a landscape device to the the available device pool.
        """
        self._ensure_activation()

        keyid = device.keyid

        if keyid not in self._checked_out_devices:
            errmsg = "Attempting to checkin a device that is not checked out. {}".format(
                device)
            raise AKitSemanticError(errmsg)

        self.landscape_lock.acquire()
        try:
            self._device_pool[keyid] = device
            del self._checked_out_devices[keyid]
        finally:
            self.landscape_lock.release()

        return
示例#28
0
    def checkin_multiple_devices(self, devices: List[LandscapeDevice]):
        """
            Returns a landscape device to the the available device pool.
        """
        self._ensure_activation()

        checkin_errors = []

        self.landscape_lock.acquire()
        try:

            for dev in devices:
                keyid = dev.keyid

                if keyid not in self._checked_out_devices:
                    self._device_pool[keyid] = dev
                    checkin_errors.append(dev)

            if len(checkin_errors) > 0:
                err_msg_lines = [
                    "Attempting to checkin a device that is not checked out.",
                    "DEVICES:"
                ]
                for dev in checkin_errors:
                    err_msg_lines.append("    {}".format(dev))

                err_msg = os.linesep.join(err_msg_lines)
                raise AKitSemanticError(err_msg)

            for dev in devices:
                keyid = dev.keyid

                if keyid in self._checked_out_devices:
                    self._device_pool[keyid] = dev
                    del self._checked_out_devices[keyid]

        finally:
            self.landscape_lock.release()

        return
示例#29
0
    def execute_tests(self, runid: str, recorder):
        """
            Called in order to execute the tests contained in the :class:`TestPacks` being run.
        """

        res_name = "<session>"

        self._recorder = recorder

        self._root_result = self.create_job_result_container(runid, res_name)
        recorder.record(self._root_result)

        if self._sequence_document is None:
            errmsg = "The 'execute_tests' method should not be called without first generating the test sequence document."
            raise AKitSemanticError(errmsg) from None

        # Import the test sequence document
        sequence_mod = import_file("sequence_document",
                                   self._sequence_document)
        sequence_mod.session(self)

        return
示例#30
0
    def _process_content(self):

        pattern_queue = [p for p in self.EXPECTED_LINES]
        content_queue = [cl for cl in self._content]

        if len(pattern_queue) == 0:
            errmsg = "The 'EXPECTED_LINES' list must be a list with at least one 'RegExPattern' or 'RegExMultiPattern' object."
            raise AKitSemanticError(errmsg)

        current_pattern = None
        current_line = None
        strict = None

        while len(content_queue) > 0:

            current_line = content_queue.pop(0)
            if self.CONSUME_WHITESPACE:
                while current_line.strip() == "" and len(content_queue) > 0:
                    current_line = content_queue.pop(0)

            if current_line is None:
                break

            # If pattern was set to None then we either found a match and
            # the pattern that was matched was not a repeating patter or
            # it was a repeating pattern but the repeating condition was
            # terminated due to mis-match or match for a following pattern.
            if current_pattern is None:
                if len(pattern_queue) == 0:
                    break

                current_pattern = pattern_queue.pop(0)

                strict = self._strict
                if current_pattern.strict is not None:
                    strict = current_pattern.strict

            matches = None
            if isinstance(current_pattern, RegExPattern):

                matches = self._process_pattern_simple(current_pattern,
                                                       current_line, strict)
                if matches is not None:
                    if not current_pattern.consume:
                        if current_pattern.match_type is None:
                            self._process_name_based_match(
                                current_pattern, matches)
                        else:
                            self._process_match_type_based_match(
                                current_pattern, matches)

            elif isinstance(current_pattern, RegExMultiPattern):

                matches = self._process_pattern_multimatch(
                    current_pattern, content_queue, strict)
                if matches is not None:
                    if not current_pattern.consume:
                        if current_pattern.match_type is None:
                            self._process_name_based_match(
                                current_pattern, matches)
                        else:
                            self._process_match_type_based_match(
                                current_pattern, matches)

            else:
                errmsg = "The 'EXPECTED_LINES' list must be a list of 'RegExPattern' or 'RegExMultiPattern' objects."
                raise AKitSemanticError(errmsg)

            if matches is not None:
                if not current_pattern.repeats:
                    current_pattern = None

                elif len(pattern_queue) > 0 and len(content_queue) > 0:
                    # If we are processing a repeating pattern, we need to see if the next
                    # pattern is going to match and result in a termination of the current
                    # repeating pattern.

                    preview_pattern = pattern_queue[0]
                    preview_line = self._get_preview_line(content_queue)

                    if preview_line is not None:
                        # Perform a preview operation, if the next pattern is a match for the
                        # next line then clear the current pattern
                        pmobj = None
                        if isinstance(preview_pattern, RegExPattern):
                            pmobj = preview_pattern.pattern.match(preview_line)
                        elif isinstance(preview_pattern, RegExMultiPattern):
                            pmobj = preview_pattern.patterns[0].match(
                                preview_line)
                        if pmobj is not None:
                            current_pattern = None
                    else:
                        current_pattern = None

        if len(self._pattern_misses) > 0 or len(pattern_queue) > 0:
            # We shouldn't have pattern misses, if we have a miss, let the
            # reader register bugs.
            self._pattern_misses.extend(pattern_queue)
            self._register_pattern_match_bugs()

        return