[Piglit] [RFC 22/30] profile.py: Add a context_manager to TestProfile for adding tests.

Dylan Baker baker.dylan.c at gmail.com
Tue Jan 27 14:58:56 PST 2015


This adds a very powerful method to the TestProfile class,
group_manager. This group_manager method is a context_manager (it's used
with the 'with' statement), and is passed a test class and a flattened
group name (such as one returned by grouptools.join), and yields a
callable that is used to add tests to the profile.

This gives us a lot of advantages. First, it means that tests are added
in a context, so if we need to define data structures for adding tests
to a specific group (say a list of texture formats supported by a
specific version of GL), that data structure is defined in a nested
scope, so it cannot be accidentally be used in a different group.
Second, it means not passing a group around anymore, in fact, it creates
an abstraction on top of the group data structure so it doesn't matter
how we're representing it. Third the function itself is more flexible
than anything we've had before. It can either take an explicit name, or
it can call ' '.join() on the arguments to the Test, and use that as a
name, which can help make Test assignments much less verbose.

Signed-off-by: Dylan Baker <dylanx.c.baker at intel.com>
---
 framework/profile.py             | 56 ++++++++++++++++++++++++++++++++++++++++
 framework/tests/profile_tests.py | 35 +++++++++++++++++++++++++
 framework/tests/utils.py         | 16 ++++++++++++
 3 files changed, 107 insertions(+)

diff --git a/framework/profile.py b/framework/profile.py
index a24b4fe..6c3aa41 100644
--- a/framework/profile.py
+++ b/framework/profile.py
@@ -33,6 +33,7 @@ import multiprocessing
 import multiprocessing.dummy
 import importlib
 import types
+import contextlib
 
 from framework.dmesg import get_dmesg
 from framework.log import LogManager
@@ -318,6 +319,61 @@ class TestProfile(object):
             self.tests.update(profile.tests)
             self.test_list.update(profile.test_list)
 
+    @contextlib.contextmanager
+    def group_manager(self, test_class, group):
+        """A context manager to make working with flat groups simple.
+
+        This provides a simple way to replace add_plain_test,
+        add_concurrent_test, etc. Basic usage would be to use the with
+        statement to yield and adder instance, and then add tests.
+
+        This does not provide for a couple of cases.
+        1) When you need to alter the test after initialization. If you need to
+           set instance.env, for example, you will need to do so manually. It
+           is recommended to not use this function for that case, but to
+           manually assign the test and set env together, for code clearness.
+        2) When you need to use a function that modifies profile.
+
+        Arguments:
+        test_class -- a Test derived class that. Instances of this class will
+                      be added to the profile.
+        group -- a string or unicode that will be used as the key for the test
+                 in profile.
+
+        >>> from framework.test import PiglitGLTest
+        >>> p = TestProfile()
+        >>> with p.group_manager(PiglitGLTest, 'a') as g:
+        ...     g(['test'])
+        ...     g(['power', 'test'], 'powertest')
+
+        """
+        assert isinstance(group, basestring), type(group)
+
+        def adder(args, name=None, **kwargs):
+            """Helper function that actually adds the tests.
+
+            Arguments:
+            args -- arguments to be passed to the test_class constructor.
+                    This must be appropriate for the underlying class
+
+            Keyword Arguments:
+            name -- If this is a a truthy value that value will be used as the
+                    key for the test. If name is falsy then args will be
+                    ' '.join'd and used as name. Default: None
+            kwargs -- Any additional args will be passed directly to the test
+                      constructor as keyword args.
+
+            """
+            if not name:
+                lgroup = grouptools.join(group, ' '.join(args))
+            else:
+                assert isinstance(name, basestring)
+                lgroup = grouptools.join(group, name)
+
+            self.test_list[lgroup] = test_class(args, **kwargs)
+
+        yield adder
+
 
 def load_test_profile(filename):
     """ Load a python module and return it's profile attribute
diff --git a/framework/tests/profile_tests.py b/framework/tests/profile_tests.py
index 183f526..9723c8c 100644
--- a/framework/tests/profile_tests.py
+++ b/framework/tests/profile_tests.py
@@ -31,6 +31,7 @@ import framework.core as core
 import framework.dmesg as dmesg
 import framework.profile as profile
 from framework.tests import utils
+from framework import grouptools
 
 
 def test_initialize_testprofile():
@@ -278,3 +279,37 @@ def test_matches_exclude_mar(data):
     del baseline['group3/test5']
 
     nt.assert_dict_equal(profile_.test_list, baseline)
+
+
+ at utils.no_error
+def test_testprofile_group_manager_no_name_args_eq_one():
+    """TestProfile.group_manager: no name and len(args) == 1 is valid"""
+    prof = profile.TestProfile()
+    with prof.group_manager(utils.Test, 'foo') as g:
+        g(['a'])
+
+
+def test_testprofile_group_manager_no_name_args_gt_one():
+    """TestProfile.group_manager: no name and len(args) > 1 is valid"""
+    prof = profile.TestProfile()
+    with prof.group_manager(utils.Test, 'foo') as g:
+        g(['a', 'b'])
+
+    nt.assert_in(grouptools.join('foo', 'a b'), prof.test_list)
+
+
+ at utils.no_error
+def test_testprofile_group_manager_name():
+    """TestProfile.group_manager: name plus len(args) > 1 is valid"""
+    prof = profile.TestProfile()
+    with prof.group_manager(utils.Test, 'foo') as g:
+        g(['a', 'b'], 'a')
+
+
+def test_testprofile_group_manager_is_added():
+    """TestProfile.group_manager: Tests are added to the profile"""
+    prof = profile.TestProfile()
+    with prof.group_manager(utils.Test, 'foo') as g:
+        g(['a', 'b'], 'a')
+
+    nt.assert_in(grouptools.join('foo', 'a'), prof.test_list)
diff --git a/framework/tests/utils.py b/framework/tests/utils.py
index 696e830..d95c8b0 100644
--- a/framework/tests/utils.py
+++ b/framework/tests/utils.py
@@ -337,3 +337,19 @@ def fail_if(function, values, exceptions, except_error=False):
         if not except_error:
             raise
         return None
+
+
+def no_error(func):
+    """Decorator for tests that should not raise an error.
+
+    If any error is raised then it will be converted into a TestFailure.
+
+    """
+    @functools.wraps(func)
+    def test_wrapper(*args, **kwargs):
+        try:
+            func(*args, **kwargs)
+        except Exception as e:
+            raise TestFailure(e.message)
+
+    return test_wrapper
-- 
2.2.2



More information about the Piglit mailing list