diff --git a/lisa/conf.py b/lisa/conf.py index 254f4471ebb6eeff3bc0aaabf717287f8c85cc15..685b7f933470df7b99abe2719183f63536525162 100644 --- a/lisa/conf.py +++ b/lisa/conf.py @@ -901,12 +901,22 @@ class MultiSrcConfABC(Serializable, abc.ABC): return tuple(key1[:len_]) == tuple(key2[:len_]) offending = [ - cls_.__qualname__ + cls_ for keys, cls_ in cls._REGISTERED_TOPLEVEL_KEYS.items() if eq_prefix_keys(toplevel_keys, keys) ] - if offending: + # If the offending class has the same name and was declared in the + # same module, we ignore the conflict as this is probably arising + # from an import error in that module, that lead to the module + # being re-imported again (by another import statement). + if offending and not all( + ( + cls_.__qualname__ == cls.__qualname__ and + cls_.__module__ == cls.__module__ + ) + for cls_ in offending + ): raise RuntimeError(f'Class {cls.__qualname__} cannot reuse top level key "{format_keys(toplevel_keys)}" as it is already used by {", ".join(offending)}') else: cls._REGISTERED_TOPLEVEL_KEYS[toplevel_keys] = cls diff --git a/lisa/tests/base.py b/lisa/tests/base.py index 5fe208eab21ef72e6693d58aa866b2492984d2ac..661e9d758fef9b62b88131e4766c0083f76896e1 100644 --- a/lisa/tests/base.py +++ b/lisa/tests/base.py @@ -1372,6 +1372,10 @@ class FtraceTestBundleBase(TestBundleBase): # iterations of the tests with exekall, leading to crashes. # Therefore, disable the on-disk swap. enable_swap=False, + # The event list that gets passed has already undergone namespace + # expansion when multiple ftrace conf got merged together, so there + # is no need to repeat it again. + events_namespaces=[], ) def get_trace(self, events=None, **kwargs): diff --git a/lisa/trace.py b/lisa/trace.py index e52a518558ddcf39d9a190c0c5f897b45f7b5699..63e04e8f2a859c69271250d9c0dd5f5f5f547ff0 100644 --- a/lisa/trace.py +++ b/lisa/trace.py @@ -3702,7 +3702,7 @@ class Trace(Loggable, TraceBase): self.events = events # Pre-load the selected events if events: - preload_events = AndTraceEventChecker.from_events( + preload_events = OptionalTraceEventChecker.from_events( event_ for event in events for event_ in self._expand_namespaces(event, events_namespaces) @@ -3738,24 +3738,25 @@ class Trace(Loggable, TraceBase): namespaces = self_or_cls._resolve_namespaces(namespaces) def expand(event, namespace): - if self_or_cls._is_meta_event(event): + ns_prefix = f'{namespace}__' + if not namespace: + return [event] + elif self_or_cls._is_meta_event(event): prefix, _ = event.split('@', 1) return [ f'{prefix}@{source_}' for source in self_or_cls.get_event_sources(event) for source_ in expand(source, namespace) ] + elif event.startswith(ns_prefix): + return [event] else: - return [f'{namespace}__{event}'] + return [f'{ns_prefix}{event}'] return [ event_ for namespace in namespaces - for event_ in ( - expand(event, namespace) - if namespace - else [event] - ) + for event_ in expand(event, namespace) ] _CACHEABLE_METADATA = {