[apparmor] [patch] add better loop support to common_test.py
Christian Boltz
apparmor at cboltz.de
Fri Mar 6 22:57:11 UTC 2015
Hello,
Am Mittwoch, 4. März 2015 schrieb Christian Boltz:
> Am Dienstag, 3. März 2015 schrieb Christian Boltz:
> > this patch adds better support for looping over a tests[] array to
> > common_test.py:
> > - class AATest - a base class we can use for all tests, and that
> > will
> >
> > probably get more features in the future (for example tempdir
> > handling)
> >
> > - setup_all_tests() - a function that iterates over all classes in
> > the given file and calls setup_test_loops() for each of them
> > - setup_tests_loop() - a function that creates tests based on
> > tests[]
> >
> > in the given class that call the class' _run_test() method for
> >each test specified in tests[] (inspired by setup_regex_tests() ;-)
> >
> >
> > This means we can get rid of the manually maintained tests list in
> > test-regex_matches.py and just need to call setup_all_tests() once
> > in each file.
> >
> >
> >
> > The patch also adds test-example.py, which is
> > - a demo of the code added to common_test.py
> > - a template file that we can copy for future test-*.py
> >
> >
> >
> >
> > As usual ;-) I propose this patch for trunk and 2.9
>
> setup_all_tests() really finds all classes, including imported ones
> like AppArmorBug ;-)
>
> Here's v2 that adds a ... and (isinstance(obj(),
> unittest.TestCase)): condition.
It turned out that adding
from apparmor.aa import AppArmorException
in test-*.py explodes with
Traceback (most recent call last):
File "test-example.py", line 45, in <module>
setup_all_tests()
File "/home/cb/apparmor/HEAD-clean/utils/test/common_test.py", line 58, in setup_all_tests
if inspect.isclass(obj) and (isinstance(obj(), unittest.TestCase)):
TypeError: __init__() missing 1 required positional argument: 'value'
The reason for this is that AppArmorException __init__() has an additional
parameter. This means we have to wrap "obj()" in try/except. Fortunately
this affects only non-test classes :-)
Since Seth seems to be out of counter-arguments for
12-test-loop-simplify.diff, I also merged it into this patch.
(It also affects another patch, which I'll resend in a minute.)
Here's v3, this time with the number included in the filename ;-)
[ 07-common_test_better_loop_support.diff ]
=== modified file 'utils/test/common_test.py'
--- utils/test/common_test.py 2014-11-06 20:32:49 +0000
+++ utils/test/common_test.py 2015-03-03 23:37:48 +0000
@@ -1,5 +1,6 @@
# ----------------------------------------------------------------------
# Copyright (C) 2013 Kshitij Gupta <kgupta8592 at gmail.com>
+# Copyright (C) 2015 Christian Boltz <apparmor at cboltz.de>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
@@ -12,6 +13,8 @@
#
# ----------------------------------------------------------------------
import unittest
+import inspect
import os
import re
+import sys
@@ -34,6 +36,10 @@
# print("Please press the Y button on the keyboard.")
# self.assertEqual(apparmor.common.readkey().lower(), 'y', 'Error reading key from shell!')
+
+class AATest(unittest.TestCase):
+ tests = []
+
class AAParseTest(unittest.TestCase):
parse_function = None
@@ -44,6 +50,37 @@
'parse object %s returned "%s", expected "%s"' \
%(self.parse_function.__doc__, parsed.serialize(), rule))
+
+def setup_all_tests():
+ '''call setup_tests_loop() for each class in module_name'''
+ for name, obj in inspect.getmembers(sys.modules['__main__']):
+ if inspect.isclass(obj):
+ try:
+ obj_instance = obj() # will fail for (non-test) classes with additional __init__ parameters
+ except TypeError:
+ obj_instance = None
+ if obj_instance and isinstance(obj_instance, unittest.TestCase):
+ setup_tests_loop(obj)
+
+def setup_tests_loop(test_class):
+ '''Create tests in test_class using test_class.tests and self._run_test()
+
+ test_class.tests should be tuples of (test_data, expected_results)
+ test_data and expected_results can be of any type as long as test_class._run_test()
+ know how to handle them.
+
+ A typical definition for _run_test() is:
+ def test_class._run_test(self, test_data, expected)
+ '''
+
+ for (i, (test_data, expected)) in enumerate(test_class.tests):
+ def stub_test(self, test_data=test_data, expected=expected):
+ self._run_test(test_data, expected)
+
+ stub_test.__doc__ = "test '%s'" % (test_data)
+ setattr(test_class, 'test_%d' % (i), stub_test)
+
+
def setup_regex_tests(test_class):
'''Create tests in test_class using test_class.tests and AAParseTest._test_parse_rule()
=== added file 'utils/test/test-example.py'
--- utils/test/test-example.py 1970-01-01 00:00:00 +0000
+++ utils/test/test-example.py 2015-03-03 21:05:18 +0000
@@ -0,0 +1,45 @@
+#! /usr/bin/env python
+# ------------------------------------------------------------------
+#
+# Copyright (C) 2015 Christian Boltz <apparmor at cboltz.de>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License published by the Free Software Foundation.
+#
+# ------------------------------------------------------------------
+
+import unittest
+from common_test import AATest, setup_all_tests
+
+class TestFoo(AATest):
+ tests = [
+ (0, 0 ),
+ (42, 42),
+ ]
+
+ def _run_test(self, params, expected):
+ self.assertEqual(params, expected)
+
+class TestBar(AATest):
+ tests = [
+ ('a', 'foo'),
+ ('b', 'bar'),
+ ('c', 'baz'),
+ ]
+
+ def _run_test(self, params, expected):
+ self.assertNotEqual(params, expected)
+
+ def testAdditionalBarTest(self):
+ self.assertEqual(1, 1)
+
+class TestBaz(AATest):
+ def test_Baz_only_one_test(self):
+ self.assertEqual("baz", "baz")
+
+
+
+if __name__ == '__main__':
+ setup_all_tests()
+ unittest.main(verbosity=2)
Regards,
Christian Boltz
--
> I also prefer realnames. But if people want to use a _spellable_
> alias, it's ok for me too.
> However, I hate aliases like "fE3,x7~5X" ;-)
Noone should use his/her password as a mail name ;-)
[> Christian Boltz and meister(at)netz00.com in opensuse]
More information about the AppArmor
mailing list