[svn] commit: r3184 - in /branches/trac232/src: bin/xfrin/ lib/datasrc/ lib/datasrc/python/ lib/datasrc/python/tests/ lib/datasrc/tests/

BIND 10 source code commits bind10-changes at lists.isc.org
Tue Oct 12 09:42:13 UTC 2010


Author: jelte
Date: Tue Oct 12 09:42:13 2010
New Revision: 3184

Log:
added a replaceZone() where you pass a function that provides the data to replace it with.
In the python library, this function should return an iterator
modified xfrin to use that

Modified:
    branches/trac232/src/bin/xfrin/xfrin.py.in
    branches/trac232/src/lib/datasrc/data_source.cc
    branches/trac232/src/lib/datasrc/data_source.h
    branches/trac232/src/lib/datasrc/python/libdata_source_python.cc
    branches/trac232/src/lib/datasrc/python/tests/data_source_python_test.py
    branches/trac232/src/lib/datasrc/sqlite3_datasrc.cc
    branches/trac232/src/lib/datasrc/sqlite3_datasrc.h
    branches/trac232/src/lib/datasrc/tests/sqlite3_unittest.cc

Modified: branches/trac232/src/bin/xfrin/xfrin.py.in
==============================================================================
--- branches/trac232/src/bin/xfrin/xfrin.py.in (original)
+++ branches/trac232/src/bin/xfrin/xfrin.py.in Tue Oct 12 09:42:13 2010
@@ -200,8 +200,22 @@
                 self._send_query(RRType(252))
                 #isc.datasrc.sqlite3_ds.load(self._db_file, self._zone_name,
                 #                            self._handle_xfrin_response)
-                self._handle_xfrin_response_new()
+
+                #self._handle_xfrin_response_new()
                 
+                ds = libdata_source_python.DataSrc()
+                ds.init("{ \"database_file\": \"" + self._db_file +"\" }")
+                transaction = libdata_source_python.DataSrcTransaction(ds, Name(self._zone_name), RRClass.IN())
+                result = ds.start_transaction(transaction, True)
+                
+                #result = ds.replace_zone(transaction, XfrinConnection._handle_xfrin_response, self)
+                print("[XX] Replacing zone")
+                result = ds.replace_zone(transaction, self._handle_xfrin_response)
+                print("[XX] done replacing zone")
+                #result = ds.replace_zone(transaction, test_xx_removeme)
+                 
+                result = ds.commit_transaction(transaction)
+                ds.close()
                 
                 self.log_msg(logstr + 'succeeded')
 
@@ -214,6 +228,10 @@
             self.log_msg(logstr + 'failed')
             ret = XFRIN_FAIL
             #TODO, recover data source.
+        except libdata_source_python.DataSrcError as dse:
+            self.log_msg(dse)
+            self.log_msg(logstr + 'failed')
+            ret = XFRIN_FAIL
         except isc.datasrc.sqlite3_ds.Sqlite3DSError as e:
             self.log_msg(e)
             self.log_msg(logstr + 'failed')
@@ -292,7 +310,11 @@
 
     def _handle_xfrin_response(self):
         '''Return a generator for the response to a zone transfer. '''
-        while True:
+        done = False
+        print("[XX] HANDLE generator called")
+        sys.stdout.flush()
+        soa_seen = False
+        while not done:
             data_len = self._get_request_response(2)
             msg_len = socket.htons(struct.unpack('H', data_len)[0])
             recvdata = self._get_request_response(msg_len)
@@ -301,8 +323,39 @@
             self._check_response_status(msg)
             
             answer_section = msg.get_section(Section.ANSWER())
-            for rr in self._handle_answer_section(answer_section):
-                yield rr
+            print("[XX] LIST:")
+            for a in answer_section:
+                print(a)
+            for rrset in answer_section:
+                print("[XX] Type: " + rrset.get_type().to_text() + " soa seen: " + str(soa_seen))
+                sys.stdout.flush()
+                if rrset.get_type() == RRType.SOA():
+                    print("[XX] SOA!")
+                    sys.stdout.flush()
+                    if soa_seen:
+                        # second one, we're done.
+                        print("[XX] Second SOA, done!")
+                        done = True
+                        break
+                    elif rrset.get_rdata_count() == 2:
+                        # workaround for current problem where second
+                        # soa rr gets added by the parse to the first
+                        done = True
+                        new_soa = RRset(rrset.get_name(), rrset.get_class(),
+                                        rrset.get_type(), rrset.get_ttl())
+                        new_soa.add_rdata(rrset.get_rdata()[0])
+                        print("[XX] YIELDING: ")
+                        print(new_soa)
+                        sys.stdout.flush()
+                        yield new_soa
+                    else:
+                        print("[XX] first soa")
+                        sys.stdout.flush()
+                        soa_seen = True
+                print("[XX] YIELDING: ")
+                print(rrset)
+                sys.stdout.flush()
+                yield rrset
 
             if self._soa_rr_count == 2:
                 break
@@ -320,12 +373,22 @@
         self._check_response_status(msg)
         
         answer_section = msg.get_section(Section.ANSWER())
+
+        # tmp workaround until we can do this right (both soa rrs
+        # are put as one rrset in the beginning of the message)
+        soa_rrset = answer_section[0]
+        new_soa = RRset(soa_rrset.get_name(), soa_rrset.get_class(),
+                        soa_rrset.get_type(), soa_rrset.get_ttl())
+        new_soa.add_rdata(soa_rrset.get_rdata()[0])
+        answer_section[0] = new_soa
+        
         ds = libdata_source_python.DataSrc()
         ds.init("{ \"database_file\": \"" + self._db_file +"\" }")
         transaction = libdata_source_python.DataSrcTransaction(ds, Name(self._zone_name), RRClass.IN())
-        result = ds.start_transaction(transaction)
-        result = ds.do_ixfr(transaction, answer_section)
-
+        result = ds.start_transaction(transaction, True)
+        
+        result = ds.replace_zone(transaction, answer_section)
+        
         result = ds.commit_transaction(transaction)
         ds.close()
 

Modified: branches/trac232/src/lib/datasrc/data_source.cc
==============================================================================
--- branches/trac232/src/lib/datasrc/data_source.cc (original)
+++ branches/trac232/src/lib/datasrc/data_source.cc Tue Oct 12 09:42:13 2010
@@ -1303,6 +1303,14 @@
     return (W_NOT_IMPLEMENTED);
 }
 
+DataSrc::WriteResult
+DataSrc::replaceZone(DataSrcTransaction& transaction UNUSED_PARAM,
+                     isc::dns::RRsetPtr nextRRset(void*, void*) UNUSED_PARAM,
+                     void* arg1 UNUSED_PARAM, void* arg2 UNUSED_PARAM)
+{
+    return (W_NOT_IMPLEMENTED);
+}
+
 static bool
 equalRRsets(ConstRRsetPtr a, ConstRRsetPtr b) {
     if (a->getName() != b->getName() ||
@@ -1476,8 +1484,14 @@
     }
 
     RRsetIterator rrsets = start;
+    if (rrsets == end) {
+        return (DataSrc::ERROR);
+    }
     RRsetPtr final_soa = *rrsets;
     rrsets++;
+    if (rrsets == end) {
+        return (DataSrc::ERROR);
+    }
     RRsetPtr first_soa = *rrsets;
     rrsets++;
     if (first_soa->getType() == RRType::SOA()) {
@@ -1701,5 +1715,13 @@
     return (W_NOT_IMPLEMENTED);
 }
 
-}
-}
+DataSrc::WriteResult
+MetaDataSrc::replaceZone(DataSrcTransaction& transaction UNUSED_PARAM,
+                         isc::dns::RRsetPtr nextRRset(void*, void*) UNUSED_PARAM,
+                         void* arg1 UNUSED_PARAM, void* arg2 UNUSED_PARAM)
+{
+    return (W_NOT_IMPLEMENTED);
+}
+
+}
+}

Modified: branches/trac232/src/lib/datasrc/data_source.h
==============================================================================
--- branches/trac232/src/lib/datasrc/data_source.h (original)
+++ branches/trac232/src/lib/datasrc/data_source.h Tue Oct 12 09:42:13 2010
@@ -420,9 +420,27 @@
     /// rrsets.
     /// This deletes *all* current RRsets in the zone.
     /// \param transaction The transaction to perform the operations on
+    /// \param rrsets The full set of rrsets to replace the zone with
     /// \return W_SUCCESS on success
     virtual WriteResult replaceZone(DataSrcTransaction&  transaction,
                                     const isc::dns::RRsetContainer& rrsets);
+
+    /// \brief Replace the contents of the zone by the rrsets returned
+    /// by the given function callback.
+    /// The provided function should return exactly one RRsetPtr on
+    /// each call. It 
+    /// This deletes *all* current RRsets in the zone.
+    /// \param transaction The transaction to perform the operations on
+    /// \param nextRRset Function that returns the next RRsetPtr on
+    ///        each call to it
+    /// \param arg1 This will be passed as the first argument to the
+    ///             nextRRset function (defaults to NULL)
+    /// \param arg2 This will be passed as the second argument to the
+    ///             nextRRset function (defaults to NULL)
+    /// \return W_SUCCESS on success
+    virtual WriteResult replaceZone(DataSrcTransaction& transaction,
+                                    isc::dns::RRsetPtr nextRRset(void*, void*),
+                                    void* arg1 = NULL, void* arg2 = NULL);
     //@}
 
     /// \name High-level functions for writable data sources
@@ -465,14 +483,15 @@
     virtual isc::dns::Rcode updateProcessUpdate(DataSrcTransaction& transaction,
                                         isc::dns::RRsetPtr update);
 
-    /// \brief Perform an IXFR operation
+    /// \brief Perform an IXFR operation directly from a dns message
+    /// section iterator
     /// The given RRset iterator should point to the section of the
     /// IXFR answer, and is processed as described in RFC1995
     /// \param transaction the transaction to perform the operation in
     /// \param start The start of the rrset iterator to handle
     /// \param end the end of the rrset iterator to handle
     /// \return SUCCESS on success, ERROR on failure.
-    virtual Result doIXFR(DataSrcTransaction&  transaction,
+    virtual Result doIXFR(DataSrcTransaction& transaction,
                           const isc::dns::RRsetIterator start,
                           const isc::dns::RRsetIterator end);
 
@@ -568,6 +587,9 @@
     virtual WriteResult delZone(DataSrcTransaction&  transaction);
     virtual WriteResult replaceZone(DataSrcTransaction&  transaction,
                                     const isc::dns::RRsetContainer& rrsets);
+    virtual WriteResult replaceZone(DataSrcTransaction& transaction,
+                                    isc::dns::RRsetPtr nextRRset(void*, void*),
+                                    void* arg1 = NULL, void* arg2 = NULL);
     // end of writable data sources part
 private:
     std::vector<ConstDataSrcPtr> data_sources;

Modified: branches/trac232/src/lib/datasrc/python/libdata_source_python.cc
==============================================================================
--- branches/trac232/src/lib/datasrc/python/libdata_source_python.cc (original)
+++ branches/trac232/src/lib/datasrc/python/libdata_source_python.cc Tue Oct 12 09:42:13 2010
@@ -819,10 +819,16 @@
 static PyObject*
 DataSrc_startTransaction(s_DataSrc* self, PyObject* args) {
     s_DataSrcTransaction *transaction;
-    if (PyArg_ParseTuple(args, "O!",
-                         &datasrc_transaction_type, &transaction)) {
+    PyObject* py_create_zone = NULL;
+    if (PyArg_ParseTuple(args, "O!|O",
+                         &datasrc_transaction_type, &transaction,
+                         &py_create_zone)) {
+        bool create_zone = false;
+        if (py_create_zone && PyObject_IsTrue(py_create_zone)) {
+            create_zone = true;
+        }
         PyObject* result = Py_BuildValue("I", self->datasrc->startTransaction(
-                              *(transaction->datasrc_transaction)));
+                              *(transaction->datasrc_transaction), create_zone));
         // We increase the reference count, since the transaction
         // object contains a reference to the data source
         // The corresponding DECREF is in commit/rollback
@@ -916,34 +922,100 @@
     
 }
 
+/// only used in the callback iterator to signal to the wrapping
+/// function that an object is not an RRset
+class NotRRsetException : public std::exception {};
+
+isc::dns::RRsetPtr
+callback_iterator(void* arg1, void* arg2)
+{
+    PyObject* iterator = reinterpret_cast<PyObject*>(arg1);
+    std::cout << "[XX] Getting next value from iterator" << std::endl;
+    PyObject* rrset_obj = PyIter_Next(iterator);
+    std::cout << "[XX] got next value from iterator" << std::endl;
+    if (rrset_obj) {
+        if (PyRRset_Check(rrset_obj)) {
+            return PyRRset_AsRRsetPtr(rrset_obj);
+        } else {
+            throw NotRRsetException();
+        }
+    } else {
+        return isc::dns::RRsetPtr();
+    }
+}
+
 static PyObject*
 DataSrc_replaceZone(s_DataSrc* self, PyObject* args) {
     s_DataSrcTransaction *transaction;
-    PyObject *rrset_list_obj;
-    
-    if (PyArg_ParseTuple(args, "O!O",
+    PyObject* rrset_list_or_function_obj;
+    PyObject* arg1 = NULL;
+    PyObject* arg2 = NULL;
+    
+    if (PyArg_ParseTuple(args, "O!O|OO",
                          &datasrc_transaction_type, &transaction,
-                         &rrset_list_obj)) {
-        if (!PyList_Check(rrset_list_obj)) {
-            PyErr_SetString(PyExc_TypeError,
-                            "argument 2 of replace_zone() is not a List");
-            return (NULL);
-        }
-        isc::dns::RRsetContainer rrset_list;
-        for (int i = 0; i < PyList_Size(rrset_list_obj); ++i) {
-            PyObject* rrset_obj = PyList_GET_ITEM(rrset_list_obj, i);
-            if (!PyRRset_Check(rrset_obj)) {
-                PyErr_SetString(PyExc_TypeError,
-                    "non-RRset object in argument 2 of replace_zone()");
+                         &rrset_list_or_function_obj,
+                         &arg1, &arg2)) {
+        if (PyList_Check(rrset_list_or_function_obj)) {
+            std::cout << "[XX] list argument" << std::endl;
+            isc::dns::RRsetContainer rrset_list;
+            for (int i = 0; i < PyList_Size(rrset_list_or_function_obj); ++i) {
+                PyObject* rrset_obj = PyList_GET_ITEM(rrset_list_or_function_obj, i);
+                if (!PyRRset_Check(rrset_obj)) {
+                    PyErr_SetString(PyExc_TypeError,
+                        "non-RRset object in argument 2 of replace_zone()");
+                    return (NULL);
+                }
+                rrset_list.addRRset(PyRRset_AsRRsetPtr(rrset_obj));
+            }
+            PyObject* result = Py_BuildValue("I",
+                                  self->datasrc->replaceZone(
+                                  *(transaction->datasrc_transaction),
+                                  rrset_list));
+            return (result);
+        } else if (PyCallable_Check(rrset_list_or_function_obj)) {
+            std::cout << "[XX] callable argument" << std::endl;
+            PyObject* iterator = PyObject_CallFunctionObjArgs(rrset_list_or_function_obj, arg1, arg2, NULL);
+            if (!iterator) {
                 return (NULL);
             }
-            rrset_list.addRRset(PyRRset_AsRRsetPtr(rrset_obj));
-        }
-        PyObject* result = Py_BuildValue("I",
-                              self->datasrc->replaceZone(
-                              *(transaction->datasrc_transaction),
-                              rrset_list));
-        return (result);
+            if (!PyIter_Check(iterator)) {
+                PyErr_SetString(PyExc_TypeError,
+                    "Callback in replace_zone() is not an iterator");
+                return (NULL);
+            }
+            try {
+                PyObject* result = Py_BuildValue("I",
+                                      self->datasrc->replaceZone(
+                                      *(transaction->datasrc_transaction),
+                                      callback_iterator,
+                                      iterator, NULL
+                                      ));
+                return (result);
+            } catch (NotRRsetException) {
+                PyErr_SetString(PyExc_TypeError,
+                    "non-RRset object returned by iterator in replace_zone()");
+                return (NULL);
+            }
+            /*
+            PyObject* rrset_obj;
+            while (rrset_obj = PyIter_Next(iterator)) {
+                std::cout << "[XX] GOT OBJ!" << std::endl;
+                //std::cout << PyObject_Dir(rrset_obj) << std::endl;
+                if (!PyRRset_Check(rrset_obj)) {
+                    PyErr_SetString(PyExc_TypeError,
+                        "non-RRset object returned by iterator in replace_zone()");
+                    return (NULL);
+                }
+            }
+            PyErr_SetString(PyExc_TypeError,
+                "Callable!!!");
+            return (NULL);
+            */
+        } else {
+            PyErr_SetString(PyExc_TypeError,
+                            "argument 2 of replace_zone() is not a List or a function");
+            return (NULL);
+        }
     }
     return (NULL);
 }

Modified: branches/trac232/src/lib/datasrc/python/tests/data_source_python_test.py
==============================================================================
--- branches/trac232/src/lib/datasrc/python/tests/data_source_python_test.py (original)
+++ branches/trac232/src/lib/datasrc/python/tests/data_source_python_test.py Tue Oct 12 09:42:13 2010
@@ -23,6 +23,14 @@
 from libdata_source_python import *
 from pydnspp import *
 
+def get_new_rrs(list):
+    print("[XX] GET_NEW_RRS CALLED")
+    for l in list:
+        print("[XX] get_new_rrs list item: ")
+        print(l)
+        yield l
+
+
 class DataSourceTest(unittest.TestCase):
     def setUp(self):
         self.ds = DataSrc()
@@ -338,7 +346,7 @@
         result = self.ds.start_transaction(transaction)
         self.assertEqual(DataSrc.W_NO_SUCH_ZONE, result)
         
-    def test_replace_zone(self):
+    def test_replace_zone_list(self):
         transaction = DataSrcTransaction(self.ds, Name("example.com"), RRClass.IN())
         result = self.ds.start_transaction(transaction)
         self.assertEqual(DataSrc.W_SUCCESS, result)
@@ -363,6 +371,45 @@
         n = self.ds.find_rrset(Name("www.example.com"), RRClass.IN(), RRType.A(), result, 0, Name("example.com"))
         self.assertEqual(DataSrc.SUCCESS, n);
         self.assertEqual(0, len(result))
+
+    def test_replace_zone_function(self):
+        transaction = DataSrcTransaction(self.ds, Name("example.com"), RRClass.IN())
+        result = self.ds.start_transaction(transaction)
+        self.assertEqual(DataSrc.W_SUCCESS, result)
+
+        result = []
+        n = self.ds.find_rrset(Name("www.example.com"), RRClass.IN(), RRType.A(), result, 0, Name("example.com"))
+        self.assertEqual(DataSrc.SUCCESS, n);
+        self.assertEqual(1, len(result))
+
+        result = []
+        n = self.ds.find_rrset(Name("example.com"), RRClass.IN(), RRType.SOA(), result, 0, Name("example.com"))
+        self.assertEqual(DataSrc.SUCCESS, n);
+        self.assertEqual(1, len(result))
+
+        rrset1 = result[0]
+        rrset2 = RRset(Name("added.example.com"), RRClass.IN(), RRType.A(), RRTTL(3600))
+        rrset2.add_rdata(Rdata(rrset2.get_type(), rrset2.get_class(), "192.0.2.1"))
+        rrset3 = RRset(Name("added2.example.com"), RRClass.IN(), RRType.A(), RRTTL(3600))
+        rrset3.add_rdata(Rdata(rrset3.get_type(), rrset3.get_class(), "192.0.2.2"))
+
+        new_rrs = [ rrset1, rrset2, rrset3 ]
+
+        print("[XX] About to call replace_zone with function")
+        result = self.ds.replace_zone(transaction, get_new_rrs, new_rrs)
+        self.assertEqual(DataSrc.W_SUCCESS, result)
+
+        result = self.ds.commit_transaction(transaction)
+        self.assertEqual(DataSrc.W_SUCCESS, result)
+
+        result = []
+        n = self.ds.find_rrset(Name("www.example.com"), RRClass.IN(), RRType.A(), result, 0, Name("example.com"))
+        self.assertEqual(DataSrc.SUCCESS, n);
+        self.assertEqual(0, len(result))
+
+        n = self.ds.find_rrset(Name("added.example.com"), RRClass.IN(), RRType.A(), result, 0, Name("example.com"))
+        self.assertEqual(DataSrc.SUCCESS, n);
+        self.assertEqual(1, len(result))
 
     def test_have_rrset(self):
         transaction = DataSrcTransaction(self.ds, Name("example.com"), RRClass.IN())

Modified: branches/trac232/src/lib/datasrc/sqlite3_datasrc.cc
==============================================================================
--- branches/trac232/src/lib/datasrc/sqlite3_datasrc.cc (original)
+++ branches/trac232/src/lib/datasrc/sqlite3_datasrc.cc Tue Oct 12 09:42:13 2010
@@ -979,6 +979,7 @@
             rdp->next();
         }
     } while (!rdp->isLast());
+    std::cout << "[XX] added rrset to zone " << zone_id << ": " << rrset->toText() << std::endl;
     return result;
 }
 
@@ -1139,6 +1140,37 @@
     while (it != rrsets.end()) {
         result = addRRset(transaction, *it);
         if (result != DataSrc::W_SUCCESS) {
+            return result;
+        }
+        it++;
+    }
+    return DataSrc::W_SUCCESS;
+}
+
+DataSrc::WriteResult
+Sqlite3DataSrc::replaceZone(DataSrcTransaction& transaction,
+                            isc::dns::RRsetPtr nextRRset(void*, void*),
+                            void* arg1, void* arg2)
+{
+    if (transaction.getState() != DataSrcTransaction::RUNNING) {
+        std::cout << "[XX] Transaction not running" << std::endl;
+        return DataSrc::W_ERROR;
+    }
+
+    int zone_id = transaction.getData()->get("zone_id")->intValue();
+
+    DataSrc::WriteResult result = delAll(zone_id);
+    if (result != DataSrc::W_SUCCESS) {
+        std::cout << "[XX] delAll failed" << std::endl;
+        return result;
+    }
+
+    RRsetPtr next_rrset;
+    while (next_rrset = nextRRset(arg1, arg2)) {
+        std::cout << "[XX] adding rrset: " << next_rrset->toText() << std::endl;
+        result = addRRset(transaction, next_rrset);
+        if (result != DataSrc::W_SUCCESS) {
+            std::cout << "[XX] addrrset failed" << std::endl;
             return result;
         }
     }

Modified: branches/trac232/src/lib/datasrc/sqlite3_datasrc.h
==============================================================================
--- branches/trac232/src/lib/datasrc/sqlite3_datasrc.h (original)
+++ branches/trac232/src/lib/datasrc/sqlite3_datasrc.h Tue Oct 12 09:42:13 2010
@@ -118,6 +118,9 @@
                                isc::dns::ConstRRsetPtr rrset);
     WriteResult replaceZone(DataSrcTransaction& transaction,
                             const isc::dns::RRsetContainer& rrsets);
+    WriteResult replaceZone(DataSrcTransaction& transaction,
+                            isc::dns::RRsetPtr nextRRset(void*, void*),
+                            void* arg1 = NULL, void* arg2 = NULL);
     WriteResult delZone(DataSrcTransaction& transaction);
 
 private:

Modified: branches/trac232/src/lib/datasrc/tests/sqlite3_unittest.cc
==============================================================================
--- branches/trac232/src/lib/datasrc/tests/sqlite3_unittest.cc (original)
+++ branches/trac232/src/lib/datasrc/tests/sqlite3_unittest.cc Tue Oct 12 09:42:13 2010
@@ -13,6 +13,8 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 // $Id$
+
+#include <config.h>
 
 #include <stdint.h>
 
@@ -1106,7 +1108,7 @@
     EXPECT_EQ(DataSrc::NAME_NOT_FOUND, find_flags);
 }
 
-TEST_F(Sqlite3DataSourceTest, replaceZone) {
+TEST_F(Sqlite3DataSourceTest, replaceZone_container) {
     // reset database
     ASSERT_EQ(0, install_writable_database());
 
@@ -1149,6 +1151,133 @@
     EXPECT_EQ(DataSrc::NAME_NOT_FOUND, find_flags);
     EXPECT_EQ(1, result_sets.size());
 
+}
+
+RRsetPtr
+getRRsetCallback_empty(void *arg1 UNUSED_PARAM,
+                       void* arg2 UNUSED_PARAM) {
+    return RRsetPtr();
+}
+
+TEST_F(Sqlite3DataSourceTest, replaceZone_callback_empty) {
+    // reset database
+    ASSERT_EQ(0, install_writable_database());
+
+    // use our copied writable datasource db
+    ASSERT_EQ(DataSrc::SUCCESS, data_source.close());
+    ASSERT_EQ(DataSrc::SUCCESS, data_source.init(SQLITE_DBFILE_WRITE));
+
+    // check whether an A exists
+    EXPECT_EQ(DataSrc::SUCCESS,
+              data_source.findRRset(www_name, RRClass::IN(), RRType::A(),
+                                    result_sets, find_flags, &zone_name));
+    EXPECT_EQ(DataSrc::SUCCESS, find_flags);
+    EXPECT_EQ(1, result_sets.size());
+
+    // Replace them, roll back
+    DataSrcTransaction transaction1(&data_source, zone_name, RRClass::IN());
+    ASSERT_EQ(DataSrc::W_SUCCESS, data_source.startTransaction(transaction1));
+    ASSERT_EQ(DataSrc::W_SUCCESS, data_source.replaceZone(transaction1, getRRsetCallback_empty));
+    ASSERT_EQ(DataSrc::W_SUCCESS, data_source.rollbackTransaction(transaction1));
+
+    // check whether it still exists
+    EXPECT_EQ(DataSrc::SUCCESS,
+              data_source.findRRset(www_name, RRClass::IN(), RRType::A(),
+                                    result_sets, find_flags, &zone_name));
+    EXPECT_EQ(DataSrc::SUCCESS, find_flags);
+    EXPECT_EQ(1, result_sets.size());
+
+    // Replace them, commit
+    DataSrcTransaction transaction2(&data_source, zone_name, RRClass::IN());
+    ASSERT_EQ(DataSrc::W_SUCCESS, data_source.startTransaction(transaction2));
+    ASSERT_EQ(DataSrc::W_SUCCESS, data_source.replaceZone(transaction2, getRRsetCallback_empty));
+    ASSERT_EQ(DataSrc::W_SUCCESS, data_source.commitTransaction(transaction2));
+    
+    // check whether it's gone now
+    EXPECT_EQ(DataSrc::SUCCESS,
+              data_source.findRRset(www_name, RRClass::IN(), RRType::A(),
+                                    result_sets, find_flags, &zone_name));
+    EXPECT_EQ(DataSrc::NAME_NOT_FOUND, find_flags);
+    EXPECT_EQ(1, result_sets.size());
+
+}
+
+RRsetPtr
+getRRsetCallback_vector(void *arg1,
+                        void *arg2)
+{
+    //std::vector<RRsetPtr> v = static_cast<std::vector<RRsetPtr> >(arg1);
+    std::vector<RRsetPtr>* v = reinterpret_cast<std::vector<RRsetPtr>* >(arg1);
+    size_t* i = reinterpret_cast<size_t*>(arg2);
+    std::cout << "[XX] getRRsetCallback_vector() called" << std::endl;
+    std::cout << "[XX] i: " << *i << std::endl;
+
+    if (*i < v->size()) {
+        return ((*v)[(*i)++]);
+    } else {
+        return (RRsetPtr());
+    }
+}
+
+TEST_F(Sqlite3DataSourceTest, replaceZone_callback_vector) {
+    std::vector<RRsetPtr> rrsets;
+
+    size_t i = 0;
+    
+    // reset database
+    ASSERT_EQ(0, install_writable_database());
+
+    // use our copied writable datasource db
+    ASSERT_EQ(DataSrc::SUCCESS, data_source.close());
+    ASSERT_EQ(DataSrc::SUCCESS, data_source.init(SQLITE_DBFILE_WRITE));
+
+    // Let's take the existing SOA for now
+    RRsetList soa_rrset;
+    EXPECT_EQ(DataSrc::SUCCESS,
+              data_source.findExactRRset(zone_name, RRClass::IN(), RRType::SOA(),
+                                    soa_rrset, find_flags, &zone_name));
+    ASSERT_EQ(DataSrc::SUCCESS, find_flags);
+    ASSERT_EQ(1, soa_rrset.size());
+
+    rrsets.push_back(soa_rrset.findRRset(RRType::SOA(), RRClass::IN()));
+    rrsets.push_back(new_rrset);
+
+    // Replace them, roll back
+    DataSrcTransaction transaction1(&data_source, zone_name, RRClass::IN());
+    ASSERT_EQ(DataSrc::W_SUCCESS, data_source.startTransaction(transaction1));
+    ASSERT_EQ(DataSrc::W_SUCCESS, data_source.replaceZone(transaction1, getRRsetCallback_vector, &rrsets, &i));
+    ASSERT_EQ(DataSrc::W_SUCCESS, data_source.rollbackTransaction(transaction1));
+
+    // check whether it still exists
+    EXPECT_EQ(DataSrc::SUCCESS,
+              data_source.findRRset(www_name, RRClass::IN(), RRType::A(),
+                                    result_sets, find_flags, &zone_name));
+    EXPECT_EQ(DataSrc::SUCCESS, find_flags);
+    EXPECT_EQ(1, result_sets.size());
+
+    // Replace them, commit
+    i = 0;
+    DataSrcTransaction transaction2(&data_source, zone_name, RRClass::IN());
+    ASSERT_EQ(DataSrc::W_SUCCESS, data_source.startTransaction(transaction2));
+    ASSERT_EQ(DataSrc::W_SUCCESS, data_source.replaceZone(transaction2, getRRsetCallback_vector, &rrsets, &i));
+    ASSERT_EQ(DataSrc::W_SUCCESS, data_source.commitTransaction(transaction2));
+    
+    // check whether the original rrs are gone now
+    EXPECT_EQ(DataSrc::SUCCESS,
+              data_source.findRRset(www_name, RRClass::IN(), RRType::A(),
+                                    result_sets, find_flags, &zone_name));
+    EXPECT_EQ(DataSrc::NAME_NOT_FOUND, find_flags);
+    EXPECT_EQ(1, result_sets.size());
+    
+    // and check if the new record exists
+    EXPECT_EQ(DataSrc::SUCCESS,
+              data_source.findExactRRset(new_rrset->getName(), new_rrset->getClass(), new_rrset->getType(),
+                                    result_sets, find_flags, &zone_name));
+    //std::cout << "[XX] done, exit" << std::endl;
+    //data_source.close();
+    //exit(0);
+    ASSERT_EQ(DataSrc::SUCCESS, find_flags);
+    ASSERT_EQ(1, result_sets.size());
 }
 
 TEST_F(Sqlite3DataSourceTest, delZone) {




More information about the bind10-changes mailing list