Browse Source

[1332] [1332] implement a bit more complete version of getNextDiff() with more
detailed tests. The MockAccessor was updated to have workable getDiffs().

JINMEI Tatuya 13 years ago
parent
commit
0878c77ba4
2 changed files with 114 additions and 14 deletions
  1. 41 10
      src/lib/datasrc/database.cc
  2. 73 4
      src/lib/datasrc/tests/database_unittest.cc

+ 41 - 10
src/lib/datasrc/database.cc

@@ -1095,26 +1095,57 @@ DatabaseClient::getUpdater(const isc::dns::Name& name, bool replace,
 //  source.
 //
 class DatabaseJournalReader : public ZoneJournalReader {
+private:
+    // A shortcut typedef to keep the code concise.
+    typedef DatabaseAccessor Accessor;
 public:
-    DatabaseJournalReader() {}
+    DatabaseJournalReader(shared_ptr<Accessor> accessor, const Name& zone,
+                          const RRClass& rrclass, uint32_t begin,
+                          uint32_t end) :
+        accessor_(accessor), rrclass_(rrclass)
+    {
+        const pair<bool, int> zoneinfo(accessor_->getZone(zone.toText()));
+        if (!zoneinfo.first) {
+            // No such zone, can't continue
+            isc_throw(DataSourceError, "Zone " << zone << "/"
+                      << rrclass << " doesn't exist in database: " <<
+                      accessor_->getDBName());
+        }
+        context_ = accessor_->getDiffs(zoneinfo.second, begin, end);
+    }
     virtual ~DatabaseJournalReader() {}
     virtual ConstRRsetPtr getNextDiff() {
-        return (ConstRRsetPtr());
+        // TBD: check read after completion
+
+        string data[Accessor::COLUMN_COUNT];
+        if (!context_->getNext(data)) {
+            return (ConstRRsetPtr());
+        }
+
+        RRsetPtr rrset(new RRset(Name(data[Accessor::NAME_COLUMN]), rrclass_,
+                                 RRType(data[Accessor::TYPE_COLUMN]),
+                                 RRTTL(data[Accessor::TTL_COLUMN])));
+        rrset->addRdata(rdata::createRdata(rrset->getType(), rrclass_,
+                                           data[Accessor::RDATA_COLUMN]));
+        return (rrset);
     }
+
+private:
+    shared_ptr<Accessor> accessor_;
+    const RRClass rrclass_;
+    Accessor::IteratorContextPtr context_;
 };
 
 // The JournalReader factory
 ZoneJournalReaderPtr
 DatabaseClient::getJournalReader(const isc::dns::Name& zone,
-                                 uint32_t, uint32_t) const
+                                 uint32_t begin_serial,
+                                 uint32_t end_serial) const
 {
-    const pair<bool, int> zoneinfo(accessor_->getZone(zone.toText()));
-    if (!zoneinfo.first) {
-        // No such zone, can't continue
-        isc_throw(DataSourceError, "Zone " << zone << "/" << rrclass_ <<
-                  " doesn't exist in database: " + accessor_->getDBName());
-    }
-    return (ZoneJournalReaderPtr(new DatabaseJournalReader()));
+    return (ZoneJournalReaderPtr(new DatabaseJournalReader(accessor_, zone,
+                                                           rrclass_,
+                                                           begin_serial,
+                                                           end_serial)));
 }
 }
 }

+ 73 - 4
src/lib/datasrc/tests/database_unittest.cc

@@ -33,6 +33,7 @@
 #include <testutils/dnsmessage_test.h>
 
 #include <map>
+#include <vector>
 
 using namespace isc::datasrc;
 using namespace std;
@@ -261,7 +262,7 @@ public:
 
     virtual IteratorContextPtr getDiffs(int, uint32_t, uint32_t) const {
         isc_throw(isc::NotImplemented,
-                  "This database datasource can't be iterated");
+                  "This database datasource doesn't support diffs");
     }
 
     virtual std::string findPreviousName(int, const std::string&) const {
@@ -550,6 +551,29 @@ private:
             }
         }
     };
+    class MockDiffIteratorContext : public IteratorContext {
+        const vector<JournalEntry> diffs_;
+        vector<JournalEntry>::const_iterator it_;
+    public:
+        MockDiffIteratorContext(const vector<JournalEntry>& diffs) :
+            diffs_(diffs), it_(diffs_.begin())
+        {}
+        virtual bool getNext(string (&data)[COLUMN_COUNT]) {
+            if (it_ == diffs_.end()) {
+                return (false);
+            }
+            data[DatabaseAccessor::NAME_COLUMN] =
+                (*it_).data_[DatabaseAccessor::DIFF_NAME];
+            data[DatabaseAccessor::TYPE_COLUMN] =
+                (*it_).data_[DatabaseAccessor::DIFF_TYPE];
+            data[DatabaseAccessor::TTL_COLUMN] =
+                (*it_).data_[DatabaseAccessor::DIFF_TTL];
+            data[DatabaseAccessor::RDATA_COLUMN] =
+                (*it_).data_[DatabaseAccessor::DIFF_RDATA];
+            ++it_;
+            return (true);
+        }
+    };
 public:
     virtual IteratorContextPtr getAllRecords(int id) const {
         if (id == READONLY_ZONE_ID) {
@@ -733,6 +757,26 @@ public:
         }
     }
 
+    virtual IteratorContextPtr getDiffs(int id, uint32_t start,
+                                        uint32_t end) const
+    {
+        vector<JournalEntry> selected_jnl;
+
+        for (vector<JournalEntry>::const_iterator it =
+                 journal_entries_->begin();
+             it != journal_entries_->end(); ++it)
+        {
+            // For simplicity we don't take into account serial number
+            // arithmetic; compare serials as bare unsigned integers.
+            if (id != READONLY_ZONE_ID || (*it).serial_ < start ||
+                (*it).serial_ > end) {
+                continue;
+            }
+            selected_jnl.push_back(*it);
+        }
+        return (IteratorContextPtr(new MockDiffIteratorContext(selected_jnl)));
+    }
+
     // Check the journal is as expected and clear the journal
     void checkJournal(const std::vector<JournalEntry> &expected) const {
         std::vector<JournalEntry> journal;
@@ -3009,11 +3053,36 @@ TEST_F(MockDatabaseClientTest, journalException) {
     EXPECT_THROW(updater_->deleteRRset(*soa_), DataSourceError);
 }
 
-TYPED_TEST(DatabaseClientTest, getJournalReader) {
+//
+// Tests for the ZoneJournalReader
+//
+
+TYPED_TEST(DatabaseClientTest, journalReader) {
+    // Check a simple, normal scenario: making an update from one SOA to
+    // another, and retrieve the corresponding diffs.
+    this->updater_ = this->client_->getUpdater(this->zname_, false, true);
+    this->updater_->deleteRRset(*this->soa_);
+    RRsetPtr soa_end(new RRset(this->zname_, this->qclass_, RRType::SOA(),
+                               this->rrttl_));
+    soa_end->addRdata(rdata::createRdata(RRType::SOA(), this->qclass_,
+                                         "ns1.example.org. admin.example.org. "
+                                         "1235 3600 1800 2419200 7200"));
+    this->updater_->addRRset(*soa_end);
+    this->updater_->commit();
+
     ZoneJournalReaderPtr jnl_reader(this->client_->getJournalReader(
-                                        this->zname_, 0, 1));
-    EXPECT_FALSE(jnl_reader->getNextDiff());
+                                        this->zname_, 1234, 1235));
+    ConstRRsetPtr rrset = jnl_reader->getNextDiff();
+    ASSERT_TRUE(rrset);
+    isc::testutils::rrsetCheck(this->soa_, rrset);
+    rrset = jnl_reader->getNextDiff();
+    ASSERT_TRUE(rrset);
+    isc::testutils::rrsetCheck(soa_end, rrset);
+    rrset = jnl_reader->getNextDiff();
+    ASSERT_FALSE(rrset);
+}
 
+TYPED_TEST(DatabaseClientTest, journalReaderForNXZone) {
     EXPECT_THROW(this->client_->getJournalReader(Name("nosuchzone"), 0, 1),
                  DataSourceError);
 }