From 60e51fd2764291df2332f36ff478777627d92b57 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Thu, 9 Aug 2012 10:10:42 +0200 Subject: Add python bindings for murmurhash3 --- Makefile.am | 21 +++++++-- contrib/sssd.spec.in | 1 + src/python/pysss_murmur.c | 65 +++++++++++++++++++++++++++ src/tests/pysss_murmur-test.py | 100 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 184 insertions(+), 3 deletions(-) create mode 100644 src/python/pysss_murmur.c create mode 100755 src/tests/pysss_murmur-test.py diff --git a/Makefile.am b/Makefile.am index e89938eca..726a8589f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -146,7 +146,8 @@ PYTHON_TESTS = if BUILD_PYTHON_BINDINGS PYTHON_TESTS += $(srcdir)/src/config/SSSDConfigTest.py \ - $(srcdir)/src/tests/pyhbac-test.py + $(srcdir)/src/tests/pyhbac-test.py \ + $(srcdir)/src/tests/pysss_murmur-test.py endif TESTS = \ @@ -205,7 +206,8 @@ libsss_crypt_la_LIBADD = \ if BUILD_PYTHON_BINDINGS pyexec_LTLIBRARIES = \ pysss.la \ - pyhbac.la + pyhbac.la \ + pysss_murmur.la endif dist_noinst_SCRIPTS = \ @@ -216,7 +218,8 @@ dist_noinst_SCRIPTS = \ src/config/SSSDConfigTest.py \ src/config/SSSDConfig/sssd_upgrade_config.py \ contrib/rhel/update_debug_levels.py \ - src/tests/pyhbac-test.py + src/tests/pyhbac-test.py \ + src/tests/pysss_murmur-test.py dist_noinst_DATA = \ src/config/testconfigs/sssd-valid.conf \ @@ -1539,6 +1542,18 @@ pyhbac_la_LIBADD = \ pyhbac_la_LDFLAGS = \ -avoid-version \ -module + +pysss_murmur_la_SOURCES = \ + src/python/pysss_murmur.c \ + src/util/murmurhash3.c +pysss_murmur_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(PYTHON_CFLAGS) +pysss_murmur_la_LIBADD = \ + $(PYTHON_LIBS) +pysss_murmur_la_LDFLAGS = \ + -avoid-version \ + -module endif ################ diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in index 90bd07976..838e9f54f 100644 --- a/contrib/sssd.spec.in +++ b/contrib/sssd.spec.in @@ -385,6 +385,7 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man1/sss_ssh_knownhostsproxy.1* %endif %{python_sitearch}/pysss.so +%{python_sitearch}/pysss_murmur.so %dir %{python_sitelib}/SSSDConfig %{python_sitelib}/SSSDConfig/*.py* diff --git a/src/python/pysss_murmur.c b/src/python/pysss_murmur.c new file mode 100644 index 000000000..1e89681c8 --- /dev/null +++ b/src/python/pysss_murmur.c @@ -0,0 +1,65 @@ +/* + Authors: + Sumit Bose + + Copyright (C) 2012 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include + +#include "util/murmurhash3.h" + +PyDoc_STRVAR(murmurhash3_doc, +"murmurhash3(key, key_len, seed) -> 32bit integer hash\n\ +\n\ +Calculate the murmur hash version 3 of the first key_len bytes from key\n\ +using the given seed." +); + +static PyObject * py_murmurhash3(PyObject *module, PyObject *args) +{ + const char *key; + long key_len; + long long seed; + uint32_t hash; + + if (!PyArg_ParseTuple(args, "slL", &key, &key_len, &seed)) { + PyErr_Format(PyExc_ValueError, "Invalid argument\n"); + return NULL; + } + + if (seed > UINT32_MAX || key_len > INT_MAX || key_len < 0 || + key_len > strlen(key)) { + PyErr_Format(PyExc_ValueError, "Invalid value\n"); + return NULL; + } + + hash = murmurhash3(key, key_len, seed); + + return PyLong_FromUnsignedLong((unsigned long) hash); +} + +static PyMethodDef methods[] = { + {"murmurhash3", (PyCFunction) py_murmurhash3, METH_VARARGS, murmurhash3_doc}, + {NULL,NULL, 0, NULL} +}; + + +PyMODINIT_FUNC +initpysss_murmur(void) +{ + Py_InitModule3("pysss_murmur", methods, "murmur hash functions"); +} diff --git a/src/tests/pysss_murmur-test.py b/src/tests/pysss_murmur-test.py new file mode 100755 index 000000000..715ea16b3 --- /dev/null +++ b/src/tests/pysss_murmur-test.py @@ -0,0 +1,100 @@ +#!/usr/bin/python +# SSSD +# +# Unit tests for pysss_murmur +# +# Copyright (C) Sumit Bose 2012 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import unittest +import sys +import os +import copy + +srcdir = os.getenv('builddir') +if not srcdir: + srcdir = "." +MODPATH = srcdir + "/.libs" #FIXME - is there a way to get this from libtool? + +def compat_assertItemsEqual(this, expected_seq, actual_seq, msg=None): + return this.assertEqual(sorted(expected_seq), sorted(actual_seq)) + +def compat_assertIsInstance(this, obj, cls, msg=None): + return this.assertTrue(isinstance(obj, cls)) + +# add compat methods for old unittest.TestCase versions +# (python < 2.7, RHEL5 for instance) +if not hasattr(unittest.TestCase, "assertItemsEqual"): + setattr(unittest.TestCase, "assertItemsEqual", compat_assertItemsEqual) +if not hasattr(unittest.TestCase, "assertIsInstance"): + setattr(unittest.TestCase, "assertIsInstance", compat_assertIsInstance) + +class PySssMurmurImport(unittest.TestCase): + def setUp(self): + " Make sure we load the in-tree module " + self.system_path = sys.path[:] + sys.path = [ MODPATH ] + + def tearDown(self): + " Restore the system path " + sys.path = self.system_path + + def testImport(self): + " Import the module and assert it comes from tree " + try: + import pysss_murmur + except ImportError, e: + print >>sys.stderr, "Could not load the pysss_murmur module. Please check if it is compiled" + raise e + self.assertEqual(pysss_murmur.__file__, MODPATH + "/pysss_murmur.so") + +class PySssMurmurTest(unittest.TestCase): + def testExpectedHash(self): + hash = pysss_murmur.murmurhash3("S-1-5-21-2153326666-2176343378-3404031434", 41, 0xdeadbeef) + self.assertEqual(hash, 93103853) + + def testInvalidArguments(self): + self.assertRaises(ValueError, pysss_murmur.murmurhash3, 1, 2, 3) + self.assertRaises(ValueError, pysss_murmur.murmurhash3, "test", 2) + self.assertRaises(ValueError, pysss_murmur.murmurhash3, "test") + self.assertRaises(ValueError, pysss_murmur.murmurhash3) + self.assertRaises(ValueError, pysss_murmur.murmurhash3, "test", -1, 3) + self.assertRaises(ValueError, pysss_murmur.murmurhash3, "test", 2, + 0xffffffffff) + self.assertRaises(ValueError, pysss_murmur.murmurhash3, "test", + 0xffffffffff, 3) + + +if __name__ == "__main__": + error = 0 + + suite = unittest.TestLoader().loadTestsFromTestCase(PySssMurmurImport) + res = unittest.TextTestRunner().run(suite) + if not res.wasSuccessful(): + error |= 0x1 + # need to bail out here because pysss_murmur could not be imported + sys.exit(error) + + # import the pysss_murmur module into the global namespace, but make sure + # it's the one in tree + sys.path.insert(0, MODPATH) + import pysss_murmur + + suite = unittest.TestLoader().loadTestsFromTestCase(PySssMurmurTest) + res = unittest.TextTestRunner().run(suite) + if not res.wasSuccessful(): + error |= 0x2 + + sys.exit(error) -- cgit