[apparmor] [patch 10/10] libapparmor - add python bindings tests based on C tests
Tyler Hicks
tyhicks at canonical.com
Fri Sep 6 18:45:50 UTC 2013
On 2013-09-05 01:37:05, Steve Beattie wrote:
> This patch adds tests for the swig generated python library bindings
> that reuse the C language tests.
>
> Fitting it into autotools was a bit of a trick, and is likely pretty
> brittle, as before the test script runs, it needs to know the location
> of the built libapparmor.so library, the built _LibAppArmor.so library
> and the python wrapper bits (thankfully, the latter two are the same
> directory). It's also unclear how to get autotools to emit the output of
> the test_python.py script when building, rather than just summarizing it
> as one test run.
>
> Also note that test_python.py is doing a bit of magic to automatically
> generate test case methods based on the contents of the test_multi/
> directory. This has the disadvantage of breaking tools like nosetests
> and other external tools that try to automatically detect testcases.
>
> Signed-off-by: Steve Beattie <steve at nxnw.org>
I only gave this patch a quick look, but testing more stuff can't be a
bad thing, right? :)
Acked-by: Tyler Hicks <tyhicks at canonical.com>
> ---
> libraries/libapparmor/configure.ac | 1
> libraries/libapparmor/swig/python/Makefile.am | 2
> libraries/libapparmor/swig/python/setup.py.in | 1
> libraries/libapparmor/swig/python/test/Makefile.am | 21 ++
> libraries/libapparmor/swig/python/test/test_python.py.in | 147 +++++++++++++++
> 5 files changed, 172 insertions(+)
>
> Index: b/libraries/libapparmor/swig/python/Makefile.am
> ===================================================================
> --- a/libraries/libapparmor/swig/python/Makefile.am
> +++ b/libraries/libapparmor/swig/python/Makefile.am
> @@ -2,6 +2,8 @@ if HAVE_PYTHON
>
> EXTRA_DIST = libapparmor_wrap.c
>
> +SUBDIRS = test
> +
> libapparmor_wrap.c: $(srcdir)/../SWIG/libapparmor.i
> $(SWIG) -python -I$(srcdir)/../../src -module LibAppArmor -o $@ $(srcdir)/../SWIG/libapparmor.i
> mv LibAppArmor.py __init__.py
> Index: b/libraries/libapparmor/swig/python/setup.py.in
> ===================================================================
> --- a/libraries/libapparmor/swig/python/setup.py.in
> +++ b/libraries/libapparmor/swig/python/setup.py.in
> @@ -15,4 +15,5 @@ setup(name = 'LibAppArmor',
> include_dirs=['@top_srcdir@/src'],
> extra_link_args = '-L at top_builddir@/src/.libs -lapparmor'.split(),
> )],
> + scripts = [],
> )
> Index: b/libraries/libapparmor/configure.ac
> ===================================================================
> --- a/libraries/libapparmor/configure.ac
> +++ b/libraries/libapparmor/configure.ac
> @@ -76,6 +76,7 @@ swig/perl/Makefile
> swig/perl/Makefile.PL
> swig/python/Makefile
> swig/python/setup.py
> +swig/python/test/Makefile
> swig/ruby/Makefile
> testsuite/Makefile
> testsuite/config/Makefile
> Index: b/libraries/libapparmor/swig/python/test/Makefile.am
> ===================================================================
> --- /dev/null
> +++ b/libraries/libapparmor/swig/python/test/Makefile.am
> @@ -0,0 +1,21 @@
> +if HAVE_PYTHON
> +
> +# NOTE: tests needs to exist in test/test*.py for python's setuptools
> +# not to treat it as a script to install.
> +
> +test_python.py: test_python.py.in $(top_builddir)/config.status
> + $(AM_V_GEN)cd "$(top_builddir)" && \
> + $(SHELL) ./config.status --file="swig/python/test/$@"
> + chmod +x test_python.py
> +
> +CLEANFILES = test_python.py
> +
> +# bah, how brittle is this?
> +PYTHON_DIST_BUILD_PATH = '$(builddir)/../build/$$($(PYTHON) -c "import distutils.util; import platform; print(\"lib.%s-%s\" %(distutils.util.get_platform(), platform.python_version()[:3]))")'
> +
> +TESTS = test_python.py
> +TESTS_ENVIRONMENT = \
> + LD_LIBRARY_PATH='$(top_builddir)/src/.libs:$(PYTHON_DIST_BUILD_PATH)' \
> + PYTHONPATH='$(PYTHON_DIST_BUILD_PATH)'
> +
> +endif
> Index: b/libraries/libapparmor/swig/python/test/test_python.py.in
> ===================================================================
> --- /dev/null
> +++ b/libraries/libapparmor/swig/python/test/test_python.py.in
> @@ -0,0 +1,147 @@
> +#! @PYTHON@
> +# ------------------------------------------------------------------
> +#
> +# Copyright (C) 2013 Canonical Ltd.
> +# Author: Steve Beattie <steve at nxnw.org>
> +#
> +# 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 ctypes
> +import os
> +import unittest
> +import LibAppArmor as libapparmor
> +
> +TESTDIR = "../../../testsuite/test_multi"
> +
> +# map of testsuite .out entries that aren't a simple to_lower() and
> +# s/ /_/ of the field name
> +
> +OUTPUT_MAP = {
> + 'Event type': 'event',
> + 'Mask': 'requested_mask',
> + 'Command': 'comm',
> + 'Token': 'magic_token',
> + 'ErrorCode': 'error_code',
> + 'Network family': 'net_family',
> + 'Socket type': 'net_sock_type',
> + 'Protocol': 'net_protocol',
> + 'Local addr': 'net_local_addr',
> + 'Foreign addr': 'net_foreign_addr',
> + 'Local port': 'net_local_port',
> + 'Foreign port': 'net_foreign_port',
> + 'Audit subid': 'audit_sub_id',
> +}
> +
> +# FIXME: pull this automatically out of LibAppArmor, but swig
> +# classes aren't real enough. (Perhaps we're not using swig correctly)
> +EVENT_MAP = {
> + libapparmor.AA_RECORD_ALLOWED: 'AA_RECORD_ALLOWED',
> + libapparmor.AA_RECORD_AUDIT: 'AA_RECORD_AUDIT',
> + libapparmor.AA_RECORD_DENIED: 'AA_RECORD_DENIED',
> + libapparmor.AA_RECORD_ERROR: 'AA_RECORD_ERROR',
> + libapparmor.AA_RECORD_HINT: 'AA_RECORD_HINT',
> + libapparmor.AA_RECORD_INVALID: 'AA_RECORD_INVALID',
> + libapparmor.AA_RECORD_STATUS: 'AA_RECORD_STATUS',
> +}
> +
> +# default is None if not in this table
> +NO_VALUE_MAP = {
> + 'fsuid': int(ctypes.c_ulonglong(-1).value),
> + 'ouid': int(ctypes.c_ulonglong(-1).value),
> +}
> +
> +
> +class AAPythonBindingsTests(unittest.TestCase):
> +
> + def setUp(self):
> + # REPORT ALL THE OUTPUT
> + self.maxDiff = None
> +
> + def _runtest(self, testname):
> + infile = "%s.in" % (testname)
> + outfile = "%s.out" % (testname)
> + # infile *should* only contain one line
> + with open(os.path.join(TESTDIR, infile), 'r') as f:
> + line = f.read()
> + swig_record = libapparmor.parse_record(line)
> +
> + record = self.create_record_dict(swig_record)
> + record['file'] = infile
> + libapparmor.free_record(swig_record)
> +
> + expected = self.parse_output_file(outfile)
> + self.assertEquals(expected, record,
> + "expected records did not match\n" +
> + "expected = %s\nactual = %s" % (expected, record))
> +
> + def parse_output_file(self, outfile):
> + '''parse testcase .out file and return dict'''
> +
> + output = dict()
> + with open(os.path.join(TESTDIR, outfile), 'r') as f:
> + lines = f.readlines()
> +
> + count = 0
> + for l in lines:
> + line = l.rstrip('\n')
> + count += 1
> + if line == "START":
> + self.assertEquals(count, 1,
> + "Unexpected output format in %s" % (outfile))
> + continue
> + else:
> + key, value = line.split(": ", 1)
> + if key in OUTPUT_MAP:
> + newkey = OUTPUT_MAP[key]
> + else:
> + newkey = key.lower().replace(' ', '_')
> + # check if entry already exists?
> + output[newkey] = value
> +
> + return output
> +
> + def create_record_dict(self, record):
> + '''parse the swig created record and construct a dict from it'''
> +
> + new_record = dict()
> + for key in [x for x in dir(record) if not (x.startswith('_') or x == 'this')]:
> + value = record.__getattr__(key)
> + if key == "event" and value in EVENT_MAP:
> + new_record[key] = EVENT_MAP[value]
> + elif key == "version":
> + # FIXME: out files should report log version?
> + # FIXME: or can we just deprecate v1 logs?
> + continue
> + elif key in NO_VALUE_MAP:
> + if NO_VALUE_MAP[key] == value:
> + continue
> + else:
> + new_record[key] = str(value)
> + elif record.__getattr__(key):
> + new_record[key] = str(value)
> +
> + return new_record
> +
> +
> +def find_testcases(testdir):
> + '''dig testcases out of passed directory'''
> +
> + for f in os.listdir(testdir):
> + if f.endswith(".in"):
> + yield f[:-3]
> +
> +
> +def main():
> + for f in find_testcases(TESTDIR):
> + def stub_test(self, testname=f):
> + self._runtest(testname)
> + stub_test.__doc__ = "test %s" % (f)
> + setattr(AAPythonBindingsTests, 'test_%s' % (f), stub_test)
> + return unittest.main(verbosity=2)
> +
> +if __name__ == "__main__":
> + main()
>
>
> --
> AppArmor mailing list
> AppArmor at lists.ubuntu.com
> Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20130906/6f9c7948/attachment.pgp>
More information about the AppArmor
mailing list