From: Jelte Jansen Date: Tue, 4 Dec 2012 10:33:12 +0000 (+0100) Subject: [2379] Add more tests and catches X-Git-Tag: bind10-1.0.0-beta-release~11^2^2~22 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2a98f3d106983b1e917af84747c089c5d8708df5;p=thirdparty%2Fkea.git [2379] Add more tests and catches And update doc and do a bit of style cleanup --- diff --git a/src/lib/python/isc/datasrc/Makefile.am b/src/lib/python/isc/datasrc/Makefile.am index 84da788242..934a488e38 100644 --- a/src/lib/python/isc/datasrc/Makefile.am +++ b/src/lib/python/isc/datasrc/Makefile.am @@ -20,6 +20,7 @@ datasrc_la_SOURCES += updater_python.cc updater_python.h datasrc_la_SOURCES += journal_reader_python.cc journal_reader_python.h datasrc_la_SOURCES += configurableclientlist_python.cc datasrc_la_SOURCES += configurableclientlist_python.h +datasrc_la_SOURCES += zone_loader_python.cc zone_loader_python.h datasrc_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES) datasrc_la_CXXFLAGS = $(AM_CXXFLAGS) $(PYTHON_CXXFLAGS) diff --git a/src/lib/python/isc/datasrc/__init__.py b/src/lib/python/isc/datasrc/__init__.py index 7ebd91829a..6e0f5ae202 100644 --- a/src/lib/python/isc/datasrc/__init__.py +++ b/src/lib/python/isc/datasrc/__init__.py @@ -2,7 +2,7 @@ import sys import os # The datasource factory loader uses dlopen, as does python -# for its modules. Some dynamic linkers do not play nice if +# for its modules. Some dynamic linkers do not play nice if # modules are not loaded with RTLD_GLOBAL, a symptom of which # is that exceptions are not recognized by type. So to make # sure this doesn't happen, we temporarily set RTLD_GLOBAL @@ -31,5 +31,4 @@ else: sys.setdlopenflags(flags) from isc.datasrc.sqlite3_ds import * -from isc.datasrc.master import * diff --git a/src/lib/python/isc/datasrc/client_python.cc b/src/lib/python/isc/datasrc/client_python.cc index 1a9ae4738b..71cced1a12 100644 --- a/src/lib/python/isc/datasrc/client_python.cc +++ b/src/lib/python/isc/datasrc/client_python.cc @@ -374,6 +374,16 @@ wrapDataSourceClient(DataSourceClient* client, return (container.release()); } +DataSourceClient& +PyDataSourceClient_ToDataSourceClient(PyObject* client_obj) { + if (client_obj == NULL) { + isc_throw(PyCPPWrapperException, + "obj argument NULL in Name PyObject conversion"); + } + const s_DataSourceClient* client = static_cast(client_obj); + return (*client->client); +} + } // namespace python } // namespace datasrc } // namespace isc diff --git a/src/lib/python/isc/datasrc/client_python.h b/src/lib/python/isc/datasrc/client_python.h index 71aee8b55e..09732ccbce 100644 --- a/src/lib/python/isc/datasrc/client_python.h +++ b/src/lib/python/isc/datasrc/client_python.h @@ -44,6 +44,9 @@ wrapDataSourceClient(DataSourceClient* client, LifeKeeper>& life_keeper = boost::shared_ptr()); +DataSourceClient& +PyDataSourceClient_ToDataSourceClient(PyObject* client_obj); + } // namespace python } // namespace datasrc } // namespace isc diff --git a/src/lib/python/isc/datasrc/datasrc.cc b/src/lib/python/isc/datasrc/datasrc.cc index 533a08c248..b59a6b9a66 100644 --- a/src/lib/python/isc/datasrc/datasrc.cc +++ b/src/lib/python/isc/datasrc/datasrc.cc @@ -29,6 +29,7 @@ #include "updater_python.h" #include "journal_reader_python.h" #include "configurableclientlist_python.h" +#include "zone_loader_python.h" #include #include @@ -180,6 +181,24 @@ initModulePart_ZoneIterator(PyObject* mod) { return (true); } +bool +initModulePart_ZoneLoader(PyObject* mod) { + // We initialize the static description object with PyType_Ready(), + // then add it to the module. This is not just a check! (leaving + // this out results in segmentation faults) + if (PyType_Ready(&zone_loader_type) < 0) { + return (false); + } + void* p = &zone_loader_type; + if (PyModule_AddObject(mod, "ZoneLoader", + static_cast(p)) < 0) { + return (false); + } + Py_INCREF(&zone_loader_type); + + return (true); +} + bool initModulePart_ZoneUpdater(PyObject* mod) { // We initialize the static description object with PyType_Ready(), @@ -234,8 +253,9 @@ initModulePart_ZoneJournalReader(PyObject* mod) { } PyObject* po_DataSourceError; -PyObject* po_OutOfZone; +PyObject* po_MasterFileError; PyObject* po_NotImplemented; +PyObject* po_OutOfZone; PyModuleDef iscDataSrc = { { PyObject_HEAD_INIT(NULL) NULL, 0, NULL}, @@ -260,6 +280,26 @@ PyInit_datasrc(void) { return (NULL); } + try { + po_DataSourceError = PyErr_NewException("isc.datasrc.Error", NULL, + NULL); + PyObjectContainer(po_DataSourceError).installToModule(mod, "Error"); + po_MasterFileError = PyErr_NewException("isc.datasrc.MasterFileError", + po_DataSourceError, NULL); + PyObjectContainer(po_MasterFileError).installToModule(mod, + "MasterFileError"); + po_OutOfZone = PyErr_NewException("isc.datasrc.OutOfZone", NULL, NULL); + PyObjectContainer(po_OutOfZone).installToModule(mod, "OutOfZone"); + po_NotImplemented = PyErr_NewException("isc.datasrc.NotImplemented", + NULL, NULL); + PyObjectContainer(po_NotImplemented).installToModule(mod, + "NotImplemented"); + + } catch (...) { + Py_DECREF(mod); + return (NULL); + } + if (!initModulePart_DataSourceClient(mod)) { Py_DECREF(mod); return (NULL); @@ -290,17 +330,7 @@ PyInit_datasrc(void) { return (NULL); } - try { - po_DataSourceError = PyErr_NewException("isc.datasrc.Error", NULL, - NULL); - PyObjectContainer(po_DataSourceError).installToModule(mod, "Error"); - po_OutOfZone = PyErr_NewException("isc.datasrc.OutOfZone", NULL, NULL); - PyObjectContainer(po_OutOfZone).installToModule(mod, "OutOfZone"); - po_NotImplemented = PyErr_NewException("isc.datasrc.NotImplemented", - NULL, NULL); - PyObjectContainer(po_NotImplemented).installToModule(mod, - "NotImplemented"); - } catch (...) { + if (!initModulePart_ZoneLoader(mod)) { Py_DECREF(mod); return (NULL); } diff --git a/src/lib/python/isc/datasrc/master.py b/src/lib/python/isc/datasrc/master.py index 2c22190899..d41f8727d4 100644 --- a/src/lib/python/isc/datasrc/master.py +++ b/src/lib/python/isc/datasrc/master.py @@ -182,7 +182,7 @@ def records(input): if paren == 1 or not record: continue - + ret = ' '.join(record) record = [] oldsize = size diff --git a/src/lib/python/isc/datasrc/tests/Makefile.am b/src/lib/python/isc/datasrc/tests/Makefile.am index 34af092948..93478e6df6 100644 --- a/src/lib/python/isc/datasrc/tests/Makefile.am +++ b/src/lib/python/isc/datasrc/tests/Makefile.am @@ -1,7 +1,8 @@ PYCOVERAGE_RUN = @PYCOVERAGE_RUN@ # old tests, TODO remove or change to use new API? #PYTESTS = master_test.py -PYTESTS = datasrc_test.py sqlite3_ds_test.py clientlist_test.py +PYTESTS = datasrc_test.py sqlite3_ds_test.py +PYTESTS += clientlist_test.py zone_loader_test.py EXTRA_DIST = $(PYTESTS) EXTRA_DIST += testdata/brokendb.sqlite3 diff --git a/src/lib/python/isc/datasrc/tests/zone_loader_test.py b/src/lib/python/isc/datasrc/tests/zone_loader_test.py new file mode 100644 index 0000000000..17b24d7a98 --- /dev/null +++ b/src/lib/python/isc/datasrc/tests/zone_loader_test.py @@ -0,0 +1,69 @@ +# Copyright (C) 2012 Internet Systems Consortium. +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM +# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +import isc.datasrc +import isc.dns + +import os +import unittest + +TESTDATA_PATH = os.environ['TESTDATA_PATH'] + os.sep +TESTDATA_WRITE_PATH = os.environ['TESTDATA_WRITE_PATH'] + os.sep + +READ_ZONE_DB_FILE = TESTDATA_PATH + "example.com.sqlite3" +WRITE_ZONE_DB_FILE = TESTDATA_WRITE_PATH + "rwtest.sqlite3.copied" + +READ_ZONE_DB_CONFIG = "{ \"database_file\": \"" + READ_ZONE_DB_FILE + "\" }" +WRITE_ZONE_DB_CONFIG = "{ \"database_file\": \"" + WRITE_ZONE_DB_FILE + "\"}" + +class ZoneLoaderTests(unittest.TestCase): + def setUp(self): + self.test_name = isc.dns.Name("example.com") + self.test_file = "foo.txt" + self.client = isc.datasrc.DataSourceClient("sqlite3", WRITE_ZONE_DB_CONFIG) + + def test_bad_constructor(self): + self.assertRaises(TypeError, isc.datasrc.ZoneLoader) + self.assertRaises(TypeError, isc.datasrc.ZoneLoader, 1) + self.assertRaises(TypeError, isc.datasrc.ZoneLoader, + None, self.test_name, self.test_file) + self.assertRaises(TypeError, isc.datasrc.ZoneLoader, + self.client, None, self.test_file) + self.assertRaises(TypeError, isc.datasrc.ZoneLoader, + self.client, self.test_name, None) + self.assertRaises(TypeError, isc.datasrc.ZoneLoader, + self.client, self.test_name, self.test_file, 1) + + def test_load_file(self): + #self.assertRaises(TypeError, isc.datasrc.ZoneLoader()); + loader = isc.datasrc.ZoneLoader(self.client, self.test_name, self.test_file) + # This would currently loop + #loader.load() + + def test_bad_file(self): + #self.assertRaises(TypeError, isc.datasrc.ZoneLoader()); + loader = isc.datasrc.ZoneLoader(self.client, self.test_name, "no such file") + # This would currently loop + #loader.load() + + def test_exception(self): + # Just check if masterfileerror is subclass of datasrc.Error + self.assertTrue(issubclass(isc.datasrc.MasterFileError, + isc.datasrc.Error)) + +if __name__ == "__main__": + isc.log.init("bind10") + isc.log.resetUnitTestRootLogger() + unittest.main() diff --git a/src/lib/python/isc/datasrc/zone_loader_inc.cc b/src/lib/python/isc/datasrc/zone_loader_inc.cc new file mode 100644 index 0000000000..2ea66371db --- /dev/null +++ b/src/lib/python/isc/datasrc/zone_loader_inc.cc @@ -0,0 +1,17 @@ +namespace { +const char* const ZoneLoader_doc = "\ +\n\ +\n\ +"; + +const char* const ZoneLoader_loadIncremental_doc = "\ +\n\ +\n\ +"; + +const char* const ZoneLoader_load_doc = "\ +\n\ +\n\ +"; + +} // unnamed namespace diff --git a/src/lib/python/isc/datasrc/zone_loader_python.cc b/src/lib/python/isc/datasrc/zone_loader_python.cc new file mode 100644 index 0000000000..70454dc18b --- /dev/null +++ b/src/lib/python/isc/datasrc/zone_loader_python.cc @@ -0,0 +1,192 @@ +// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +// Enable this if you use s# variants with PyArg_ParseTuple(), see +// http://docs.python.org/py3k/c-api/arg.html#strings-and-buffers +//#define PY_SSIZE_T_CLEAN + +// Python.h needs to be placed at the head of the program file, see: +// http://docs.python.org/py3k/extending/extending.html#a-simple-example +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +//#include +//#include +//#include +#include + +#include "client_python.h" +#include "datasrc.h" +#include "zone_loader_inc.cc" + +using namespace std; +using namespace isc::util::python; +using namespace isc::dns::python; +using namespace isc::datasrc; +using namespace isc::datasrc::python; + +namespace { +// The s_* Class simply covers one instantiation of the object +class s_ZoneLoader : public PyObject { +public: + s_ZoneLoader() : cppobj(NULL) {}; + ZoneLoader* cppobj; +}; + +// Shortcut type which would be convenient for adding class variables safely. +typedef CPPPyObjectContainer ZoneLoaderContainer; + +// General creation and destruction +int +ZoneLoader_init(PyObject* po_self, PyObject* args, PyObject*) { + s_ZoneLoader* self = static_cast(po_self); + PyObject *po_ds_client; + PyObject *po_name; + char* master_file; + if (PyArg_ParseTuple(args, "O!O!s", &datasourceclient_type, &po_ds_client, &name_type, &po_name, &master_file)) { + try { + self->cppobj = new ZoneLoader(PyDataSourceClient_ToDataSourceClient(po_ds_client), PyName_ToName(po_name), master_file); + return (0); + } catch (const isc::datasrc::MasterFileError& mfe) { + PyErr_SetString(getDataSourceException("MasterFileError"), mfe.what()); + } catch (const isc::datasrc::DataSourceError& dse) { + PyErr_SetString(getDataSourceException("Error"), dse.what()); + } catch (const isc::NotImplemented& ni) { + PyErr_SetString(getDataSourceException("NotImplemented"), ni.what()); + } catch (const std::exception& stde) { + PyErr_SetString(getDataSourceException("Error"), stde.what()); + } catch (...) { + PyErr_SetString(getDataSourceException("Error"), + "Unexpected exception"); + } + } + return (-1); +} + +void +ZoneLoader_destroy(PyObject* po_self) { + s_ZoneLoader* self = static_cast(po_self); + delete self->cppobj; + self->cppobj = NULL; + Py_TYPE(self)->tp_free(self); +} + +PyObject* ZoneLoader_load(PyObject* po_self, PyObject*) { + s_ZoneLoader* self = static_cast(po_self); + try { + self->cppobj->load(); + Py_RETURN_NONE; + } catch (const isc::datasrc::MasterFileError& mfe) { + PyErr_SetString(getDataSourceException("MasterFileError"), mfe.what()); + return (NULL); + } catch (const std::exception& exc) { + PyErr_SetString(getDataSourceException("Error"), exc.what()); + return (NULL); + } catch (...) { + PyErr_SetString(getDataSourceException("Error"), + "Unexpected exception"); + return (NULL); + } +} + +// This list contains the actual set of functions we have in +// python. Each entry has +// 1. Python method name +// 2. Our static function here +// 3. Argument type +// 4. Documentation +PyMethodDef ZoneLoader_methods[] = { +/* + { "get_origin", ZoneLoader_getOrigin, METH_NOARGS, + ZoneLoader_getOrigin_doc }, + { "get_class", ZoneLoader_getClass, METH_NOARGS, ZoneLoader_getClass_doc }, + { "find", ZoneLoader_find, METH_VARARGS, ZoneLoader_find_doc }, + { "find_all", ZoneLoader_find_all, METH_VARARGS, ZoneLoader_findAll_doc }, +*/ + { "load", ZoneLoader_load, METH_NOARGS, ZoneLoader_load_doc }, + { NULL, NULL, 0, NULL } +}; + +} // end of unnamed namespace + +namespace isc { +namespace datasrc { +namespace python { + +PyTypeObject zone_loader_type = { + PyVarObject_HEAD_INIT(NULL, 0) + "datasrc.ZoneLoader", + sizeof(s_ZoneLoader), // tp_basicsize + 0, // tp_itemsize + ZoneLoader_destroy, // tp_dealloc + NULL, // tp_print + NULL, // tp_getattr + NULL, // tp_setattr + NULL, // tp_reserved + NULL, // tp_repr + NULL, // tp_as_number + NULL, // tp_as_sequence + NULL, // tp_as_mapping + NULL, // tp_hash + NULL, // tp_call + NULL, // tp_str + NULL, // tp_getattro + NULL, // tp_setattro + NULL, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + ZoneLoader_doc, + NULL, // tp_traverse + NULL, // tp_clear + NULL, // tp_richcompare + 0, // tp_weaklistoffset + NULL, // tp_iter + NULL, // tp_iternext + ZoneLoader_methods, // tp_methods + NULL, // tp_members + NULL, // tp_getset + NULL, // tp_base + NULL, // tp_dict + NULL, // tp_descr_get + NULL, // tp_descr_set + 0, // tp_dictoffset + ZoneLoader_init, // tp_init + NULL, // tp_alloc + PyType_GenericNew, // tp_new + NULL, // tp_free + NULL, // tp_is_gc + NULL, // tp_bases + NULL, // tp_mro + NULL, // tp_cache + NULL, // tp_subclasses + NULL, // tp_weaklist + NULL, // tp_del + 0 // tp_version_tag +}; + +PyObject* po_MasterFileError; + +} // namespace python +} // namespace datasrc +} // namespace isc + diff --git a/src/lib/python/isc/datasrc/zone_loader_python.h b/src/lib/python/isc/datasrc/zone_loader_python.h new file mode 100644 index 0000000000..f148efa71c --- /dev/null +++ b/src/lib/python/isc/datasrc/zone_loader_python.h @@ -0,0 +1,34 @@ +// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#ifndef PYTHON_DATASRC_ZONE_LOADER_H +#define PYTHON_DATASRC_ZONE_LOADER_H 1 + +#include + +namespace isc { +namespace datasrc { + +namespace python { + +extern PyTypeObject zone_loader_type; + +} // namespace python +} // namespace datasrc +} // namespace isc +#endif // PYTHON_DATASRC_ZONE_LOADER_H + +// Local Variables: +// mode: c++ +// End: