All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] lib/oeqa: allow multiple layers to provide their own TEST_TARGET class
@ 2014-01-30  6:25 Sipke Vriend
  0 siblings, 0 replies; only message in thread
From: Sipke Vriend @ 2014-01-30  6:25 UTC (permalink / raw)
  To: stefanx.stanacar; +Cc: openembedded-core

Use a python module "folder" rather than a single module within
layers to ensure multiple layers can define a TEST_TARGET class.
Current implementation using controllers.py module will only allow
a single layer to define test targets.

Add a controllers folder as well as a TestTargetLoader class whose
job is to load the given TEST_TARGET class from any number of
python modules within the oeqa/controllers/ directory of any
layer.
The only condition will be that layers will need to ensure
the TEST_TARGET class name they provide is unique otherwise there
is no guarantee which class is instantiated. a bb.warn is used
to alude to this if it happens.

Signed-off-by: Sipke Vriend <sipke.vriend@xilinx.com>
---
 meta/lib/oeqa/controllers/__init__.py         |    3 ++
 meta/lib/oeqa/controllers/testtargetloader.py |   69 +++++++++++++++++++++++++
 meta/lib/oeqa/targetcontrol.py                |   13 ++---
 3 files changed, 79 insertions(+), 6 deletions(-)
 create mode 100644 meta/lib/oeqa/controllers/__init__.py
 create mode 100644 meta/lib/oeqa/controllers/testtargetloader.py

diff --git a/meta/lib/oeqa/controllers/__init__.py b/meta/lib/oeqa/controllers/__init__.py
new file mode 100644
index 0000000..8eda927
--- /dev/null
+++ b/meta/lib/oeqa/controllers/__init__.py
@@ -0,0 +1,3 @@
+# Enable other layers to have modules in the same named directory
+from pkgutil import extend_path
+__path__ = extend_path(__path__, __name__)
diff --git a/meta/lib/oeqa/controllers/testtargetloader.py b/meta/lib/oeqa/controllers/testtargetloader.py
new file mode 100644
index 0000000..019bbfd
--- /dev/null
+++ b/meta/lib/oeqa/controllers/testtargetloader.py
@@ -0,0 +1,69 @@
+import types
+import bb
+
+# This class is responsible for loading a test target controller
+class TestTargetLoader:
+
+    # Search oeqa.controllers module directory for and return a controller  
+    # corresponding to the given target name. 
+    # AttributeError raised if not found.
+    # ImportError raised if a provided module can not be imported.
+    def get_controller_module(self, target, bbpath):
+        controllerslist = self.get_controller_modulenames(bbpath)
+        bb.note("Available controller modules: %s" % str(controllerslist))
+        controller = self.load_controller_from_name(target, controllerslist)
+        return controller
+
+    # Return a list of all python modules in lib/oeqa/controllers for each
+    # layer in bbpath
+    def get_controller_modulenames(self, bbpath):
+
+        controllerslist = []
+
+        def add_controller_list(path):
+            if not os.path.exists(os.path.join(path, '__init__.py')):
+                bb.fatal('Controllers directory %s exists but is missing __init__.py' % path)
+            files = sorted([f for f in os.listdir(path) if f.endswith('.py') and not f.startswith('_')])
+            for f in files:
+                module = 'oeqa.controllers.' + f[:-3]
+                if module not in controllerslist:
+                    controllerslist.append(module)
+                else:
+                    bb.warn("Duplicate controller module found for %s, only one added. Layers should create unique controller module names" % module)
+
+        for p in bbpath:
+            controllerpath = os.path.join(p, 'lib', 'oeqa', 'controllers')
+            bb.debug(2, 'Searching for target controllers in %s' % controllerpath)
+            if os.path.exists(controllerpath):
+                add_controller_list(controllerpath)
+        return controllerslist
+
+    # Search for and return a controller from given target name and
+    # set of module names. 
+    # Raise AttributeError if not found.
+    # Raise ImportError if a provided module can not be imported
+    def load_controller_from_name(self, target, modulenames):
+        for name in modulenames:
+            obj = self.load_controller_from_module(target, name)
+            if obj:
+                return obj
+        raise AttributeError("Unable to load {0} from available modules: {1}".format(target, str(modulenames)))
+
+    # Search for and return a controller or None from given module name
+    def load_controller_from_module(self, target, modulename):
+        obj = None
+        # import module, allowing it to raise import exception
+        module = __import__(modulename, globals(), locals(), [target])
+        # look for target class in the module, catching any exceptions as it
+        # is valid that a module may not have the target class.
+        try:
+            obj = getattr(module, target)
+            if obj: 
+                from oeqa.targetcontrol import BaseTarget
+                if (not isinstance(obj, (type, types.ClassType))):
+                    bb.warn("Target {0} found, but not of type Class".format(target))
+                if( not issubclass(obj, BaseTarget)):
+                    bb.warn("Target {0} found, but subclass is not BaseTarget".format(target))
+        except:
+            obj = None
+        return obj
diff --git a/meta/lib/oeqa/targetcontrol.py b/meta/lib/oeqa/targetcontrol.py
index 757f9d3..ba5e6e5 100644
--- a/meta/lib/oeqa/targetcontrol.py
+++ b/meta/lib/oeqa/targetcontrol.py
@@ -11,7 +11,7 @@ import bb
 import traceback
 from oeqa.utils.sshcontrol import SSHControl
 from oeqa.utils.qemurunner import QemuRunner
-
+from oeqa.controllers.testtargetloader import TestTargetLoader
 
 def get_target_controller(d):
     testtarget = d.getVar("TEST_TARGET", True)
@@ -28,12 +28,13 @@ def get_target_controller(d):
         except AttributeError:
             # nope, perhaps a layer defined one
             try:
-                module = __import__("oeqa.utils.controllers", globals(), locals(), [testtarget])
-                controller = getattr(module, testtarget)
+                bbpath = d.getVar("BBPATH", True).split(':')
+                testtargetloader = TestTargetLoader()
+                controller = testtargetloader.get_controller_module(testtarget, bbpath)
             except ImportError as e:
-                bb.fatal("Failed to import oeqa.utils.controllers:\n%s" % traceback.format_exc())
-            except AttributeError:
-                bb.fatal("\"%s\" is not a valid value for TEST_TARGET" % testtarget)
+                bb.fatal("Failed to import {0} from available controller modules:\n{1}".format(testtarget,traceback.format_exc()))
+            except AttributeError as e:
+                bb.fatal("Invalid TEST_TARGET - " + str(e))
         return controller(d)
 
 
-- 
1.7.9.5




^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2014-01-30  6:26 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-30  6:25 [PATCH] lib/oeqa: allow multiple layers to provide their own TEST_TARGET class Sipke Vriend

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.