Browse Source

[2379] Add more tests and catches

And update doc and do a bit of style cleanup
Jelte Jansen 12 years ago
parent
commit
2a98f3d106

+ 1 - 0
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)

+ 1 - 2
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 *
 

+ 10 - 0
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<const s_DataSourceClient*>(client_obj);
+    return (*client->client);
+}
+
 } // namespace python
 } // namespace datasrc
 } // namespace isc

+ 3 - 0
src/lib/python/isc/datasrc/client_python.h

@@ -44,6 +44,9 @@ wrapDataSourceClient(DataSourceClient* client,
                      LifeKeeper>& life_keeper = boost::shared_ptr<ClientList::
                      FindResult::LifeKeeper>());
 
+DataSourceClient&
+PyDataSourceClient_ToDataSourceClient(PyObject* client_obj);
+
 } // namespace python
 } // namespace datasrc
 } // namespace isc

+ 42 - 12
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 <util/python/pycppwrapper_util.h>
 #include <dns/python/pydnspp_common.h>
@@ -181,6 +182,24 @@ initModulePart_ZoneIterator(PyObject* mod) {
 }
 
 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<PyObject*>(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(),
     // then add it to the module. This is not just a check! (leaving
@@ -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);
     }

+ 1 - 1
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

+ 2 - 1
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

+ 69 - 0
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()

+ 17 - 0
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

+ 192 - 0
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 <Python.h>
+
+#include <util/python/pycppwrapper_util.h>
+
+#include <datasrc/client.h>
+#include <datasrc/database.h>
+#include <datasrc/data_source.h>
+#include <datasrc/sqlite3_accessor.h>
+#include <datasrc/iterator.h>
+#include <datasrc/zone.h>
+#include <datasrc/zone_loader.h>
+
+#include <dns/python/name_python.h>
+//#include <dns/python/rrset_python.h>
+//#include <dns/python/rrclass_python.h>
+//#include <dns/python/rrtype_python.h>
+#include <dns/python/pydnspp_common.h>
+
+#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<s_ZoneLoader, ZoneLoader> ZoneLoaderContainer;
+
+// General creation and destruction
+int
+ZoneLoader_init(PyObject* po_self, PyObject* args, PyObject*) {
+    s_ZoneLoader* self = static_cast<s_ZoneLoader*>(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<s_ZoneLoader*>(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<s_ZoneLoader*>(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
+

+ 34 - 0
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 <Python.h>
+
+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: