Browse Source

Merge branch #1063

Michal 'vorner' Vaner 13 years ago
parent
commit
68da925f22

+ 171 - 79
src/lib/datasrc/database.cc

@@ -49,16 +49,18 @@ DatabaseClient::findZone(const Name& name) const {
     if (zone.first) {
         return (FindResult(result::SUCCESS,
                            ZoneFinderPtr(new Finder(database_,
-                                                    zone.second))));
+                                                    zone.second, name))));
     }
-    // Than super domains
+    // Then super domains
     // Start from 1, as 0 is covered above
     for (size_t i(1); i < name.getLabelCount(); ++i) {
-        zone = database_->getZone(name.split(i));
+        isc::dns::Name superdomain(name.split(i));
+        zone = database_->getZone(superdomain);
         if (zone.first) {
             return (FindResult(result::PARTIALMATCH,
                                ZoneFinderPtr(new Finder(database_,
-                                                        zone.second))));
+                                                        zone.second,
+                                                        superdomain))));
         }
     }
     // No, really nothing
@@ -66,9 +68,11 @@ DatabaseClient::findZone(const Name& name) const {
 }
 
 DatabaseClient::Finder::Finder(boost::shared_ptr<DatabaseAccessor>
-                               database, int zone_id) :
+                               database, int zone_id,
+                               const isc::dns::Name& origin) :
     database_(database),
-    zone_id_(zone_id)
+    zone_id_(zone_id),
+    origin_(origin)
 { }
 
 namespace {
@@ -162,6 +166,119 @@ private:
 };
 }
 
+std::pair<bool, isc::dns::RRsetPtr>
+DatabaseClient::Finder::getRRset(const isc::dns::Name& name,
+                                 const isc::dns::RRType* type,
+                                 bool want_cname, bool want_dname,
+                                 bool want_ns)
+{
+    RRsigStore sig_store;
+    database_->searchForRecords(zone_id_, name.toText());
+    bool records_found = false;
+    isc::dns::RRsetPtr result_rrset;
+
+    std::string columns[DatabaseAccessor::COLUMN_COUNT];
+    while (database_->getNextRecord(columns, DatabaseAccessor::COLUMN_COUNT)) {
+        if (!records_found) {
+            records_found = true;
+        }
+
+        try {
+            const isc::dns::RRType cur_type(columns[DatabaseAccessor::
+                                            TYPE_COLUMN]);
+            const isc::dns::RRTTL cur_ttl(columns[DatabaseAccessor::
+                                          TTL_COLUMN]);
+            // Ths sigtype column was an optimization for finding the
+            // relevant RRSIG RRs for a lookup. Currently this column is
+            // not used in this revised datasource implementation. We
+            // should either start using it again, or remove it from use
+            // completely (i.e. also remove it from the schema and the
+            // backend implementation).
+            // Note that because we don't use it now, we also won't notice
+            // it if the value is wrong (i.e. if the sigtype column
+            // contains an rrtype that is different from the actual value
+            // of the 'type covered' field in the RRSIG Rdata).
+            //cur_sigtype(columns[SIGTYPE_COLUMN]);
+
+            // Check for delegations before checking for the right type.
+            // This is needed to properly delegate request for the NS
+            // record itself.
+            //
+            // This happens with NS only, CNAME must be alone and DNAME
+            // is not checked in the exact queried domain.
+            if (want_ns && cur_type == isc::dns::RRType::NS()) {
+                if (result_rrset &&
+                    result_rrset->getType() != isc::dns::RRType::NS()) {
+                    isc_throw(DataSourceError, "NS found together with data"
+                              " in non-apex domain " + name.toText());
+                }
+                addOrCreate(result_rrset, name, getClass(), cur_type, cur_ttl,
+                            columns[DatabaseAccessor::RDATA_COLUMN],
+                            *database_);
+            } else if (type != NULL && cur_type == *type) {
+                if (result_rrset &&
+                    result_rrset->getType() == isc::dns::RRType::CNAME()) {
+                    isc_throw(DataSourceError, "CNAME found but it is not "
+                              "the only record for " + name.toText());
+                } else if (result_rrset && want_ns &&
+                           result_rrset->getType() == isc::dns::RRType::NS()) {
+                    isc_throw(DataSourceError, "NS found together with data"
+                              " in non-apex domain " + name.toText());
+                }
+                addOrCreate(result_rrset, name, getClass(), cur_type, cur_ttl,
+                            columns[DatabaseAccessor::RDATA_COLUMN],
+                            *database_);
+            } else if (want_cname && cur_type == isc::dns::RRType::CNAME()) {
+                // There should be no other data, so result_rrset should
+                // be empty.
+                if (result_rrset) {
+                    isc_throw(DataSourceError, "CNAME found but it is not "
+                              "the only record for " + name.toText());
+                }
+                addOrCreate(result_rrset, name, getClass(), cur_type, cur_ttl,
+                            columns[DatabaseAccessor::RDATA_COLUMN],
+                            *database_);
+            } else if (want_dname && cur_type == isc::dns::RRType::DNAME()) {
+                // There should be max one RR of DNAME present
+                if (result_rrset &&
+                    result_rrset->getType() == isc::dns::RRType::DNAME()) {
+                    isc_throw(DataSourceError, "DNAME with multiple RRs in " +
+                              name.toText());
+                }
+                addOrCreate(result_rrset, name, getClass(), cur_type, cur_ttl,
+                            columns[DatabaseAccessor::RDATA_COLUMN],
+                            *database_);
+            } else if (cur_type == isc::dns::RRType::RRSIG()) {
+                // If we get signatures before we get the actual data, we
+                // can't know which ones to keep and which to drop...
+                // So we keep a separate store of any signature that may be
+                // relevant and add them to the final RRset when we are
+                // done.
+                // A possible optimization here is to not store them for
+                // types we are certain we don't need
+                sig_store.addSig(isc::dns::rdata::createRdata(cur_type,
+                    getClass(), columns[DatabaseAccessor::RDATA_COLUMN]));
+            }
+        } catch (const isc::dns::InvalidRRType& irt) {
+            isc_throw(DataSourceError, "Invalid RRType in database for " <<
+                      name << ": " << columns[DatabaseAccessor::
+                      TYPE_COLUMN]);
+        } catch (const isc::dns::InvalidRRTTL& irttl) {
+            isc_throw(DataSourceError, "Invalid TTL in database for " <<
+                      name << ": " << columns[DatabaseAccessor::
+                      TTL_COLUMN]);
+        } catch (const isc::dns::rdata::InvalidRdataText& ird) {
+            isc_throw(DataSourceError, "Invalid rdata in database for " <<
+                      name << ": " << columns[DatabaseAccessor::
+                      RDATA_COLUMN]);
+        }
+    }
+    if (result_rrset) {
+        sig_store.appendSignatures(result_rrset);
+    }
+    return (std::pair<bool, isc::dns::RRsetPtr>(records_found, result_rrset));
+}
+
 
 ZoneFinder::FindResult
 DatabaseClient::Finder::find(const isc::dns::Name& name,
@@ -174,84 +291,61 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
     bool records_found = false;
     isc::dns::RRsetPtr result_rrset;
     ZoneFinder::Result result_status = SUCCESS;
-    RRsigStore sig_store;
+    std::pair<bool, isc::dns::RRsetPtr> found;
     logger.debug(DBG_TRACE_DETAILED, DATASRC_DATABASE_FIND_RECORDS)
         .arg(database_->getDBName()).arg(name).arg(type);
 
     try {
-        database_->searchForRecords(zone_id_, name.toText());
+        // First, do we have any kind of delegation (NS/DNAME) here?
+        Name origin(getOrigin());
+        size_t origin_label_count(origin.getLabelCount());
+        size_t current_label_count(name.getLabelCount());
+        // This is how many labels we remove to get origin
+        size_t remove_labels(current_label_count - origin_label_count);
 
-        std::string columns[DatabaseAccessor::COLUMN_COUNT];
-        while (database_->getNextRecord(columns,
-                                        DatabaseAccessor::COLUMN_COUNT)) {
-            if (!records_found) {
-                records_found = true;
+        // Now go trough all superdomains from origin down
+        for (int i(remove_labels); i > 0; --i) {
+            Name superdomain(name.split(i));
+            // Look if there's NS or DNAME (but ignore the NS in origin)
+            found = getRRset(superdomain, NULL, false, true,
+                             i != remove_labels);
+            if (found.second) {
+                // We found something redirecting somewhere else
+                // (it can be only NS or DNAME here)
+                result_rrset = found.second;
+                if (result_rrset->getType() == isc::dns::RRType::NS()) {
+                    LOG_DEBUG(logger, DBG_TRACE_DETAILED,
+                              DATASRC_DATABASE_FOUND_DELEGATION).
+                        arg(database_->getDBName()).arg(superdomain);
+                    result_status = DELEGATION;
+                } else {
+                    LOG_DEBUG(logger, DBG_TRACE_DETAILED,
+                              DATASRC_DATABASE_FOUND_DNAME).
+                        arg(database_->getDBName()).arg(superdomain);
+                    result_status = DNAME;
+                }
+                // Don't search more
+                break;
             }
+        }
 
-            try {
-                const isc::dns::RRType cur_type(columns[DatabaseAccessor::
-                                                        TYPE_COLUMN]);
-                const isc::dns::RRTTL cur_ttl(columns[DatabaseAccessor::
-                                                      TTL_COLUMN]);
-                // Ths sigtype column was an optimization for finding the
-                // relevant RRSIG RRs for a lookup. Currently this column is
-                // not used in this revised datasource implementation. We
-                // should either start using it again, or remove it from use
-                // completely (i.e. also remove it from the schema and the
-                // backend implementation).
-                // Note that because we don't use it now, we also won't notice
-                // it if the value is wrong (i.e. if the sigtype column
-                // contains an rrtype that is different from the actual value
-                // of the 'type covered' field in the RRSIG Rdata).
-                //cur_sigtype(columns[SIGTYPE_COLUMN]);
+        if (!result_rrset) { // Only if we didn't find a redirect already
+            // Try getting the final result and extract it
+            // It is special if there's a CNAME or NS, DNAME is ignored here
+            // And we don't consider the NS in origin
+            found = getRRset(name, &type, true, false, name != origin);
+            records_found = found.first;
+            result_rrset = found.second;
+            if (result_rrset && name != origin &&
 
-                if (cur_type == type) {
-                    if (result_rrset &&
-                        result_rrset->getType() == isc::dns::RRType::CNAME()) {
-                        isc_throw(DataSourceError, "CNAME found but it is not "
-                                  "the only record for " + name.toText());
-                    }
-                    addOrCreate(result_rrset, name, getClass(), cur_type,
-                                cur_ttl, columns[DatabaseAccessor::
-                                                 RDATA_COLUMN],
-                                *database_);
-                } else if (cur_type == isc::dns::RRType::CNAME()) {
-                    // There should be no other data, so result_rrset should
-                    // be empty.
-                    if (result_rrset) {
-                        isc_throw(DataSourceError, "CNAME found but it is not "
-                                  "the only record for " + name.toText());
-                    }
-                    addOrCreate(result_rrset, name, getClass(), cur_type,
-                                cur_ttl, columns[DatabaseAccessor::
-                                                 RDATA_COLUMN],
-                                *database_);
-                    result_status = CNAME;
-                } else if (cur_type == isc::dns::RRType::RRSIG()) {
-                    // If we get signatures before we get the actual data, we
-                    // can't know which ones to keep and which to drop...
-                    // So we keep a separate store of any signature that may be
-                    // relevant and add them to the final RRset when we are
-                    // done.
-                    // A possible optimization here is to not store them for
-                    // types we are certain we don't need
-                    sig_store.addSig(isc::dns::rdata::createRdata(cur_type,
-                                    getClass(),
-                                    columns[DatabaseAccessor::
-                                            RDATA_COLUMN]));
-                }
-            } catch (const isc::dns::InvalidRRType& irt) {
-                isc_throw(DataSourceError, "Invalid RRType in database for " <<
-                        name << ": " << columns[DatabaseAccessor::
-                                                TYPE_COLUMN]);
-            } catch (const isc::dns::InvalidRRTTL& irttl) {
-                isc_throw(DataSourceError, "Invalid TTL in database for " <<
-                        name << ": " << columns[DatabaseAccessor::
-                                                TTL_COLUMN]);
-            } catch (const isc::dns::rdata::InvalidRdataText& ird) {
-                isc_throw(DataSourceError, "Invalid rdata in database for " <<
-                        name << ": " << columns[DatabaseAccessor::
-                                                RDATA_COLUMN]);
+                result_rrset->getType() == isc::dns::RRType::NS()) {
+                LOG_DEBUG(logger, DBG_TRACE_DETAILED,
+                          DATASRC_DATABASE_FOUND_DELEGATION_EXACT).
+                    arg(database_->getDBName()).arg(name);
+                result_status = DELEGATION;
+            } else if (result_rrset && type != isc::dns::RRType::CNAME() &&
+                       result_rrset->getType() == isc::dns::RRType::CNAME()) {
+                result_status = CNAME;
             }
         }
     } catch (const DataSourceError& dse) {
@@ -288,7 +382,6 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
             result_status = NXDOMAIN;
         }
     } else {
-        sig_store.appendSignatures(result_rrset);
         logger.debug(DBG_TRACE_DETAILED,
                      DATASRC_DATABASE_FOUND_RRSET)
                     .arg(database_->getDBName()).arg(*result_rrset);
@@ -298,8 +391,7 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
 
 Name
 DatabaseClient::Finder::getOrigin() const {
-    // TODO Implement
-    return (Name("."));
+    return (origin_);
 }
 
 isc::dns::RRClass

+ 49 - 1
src/lib/datasrc/database.h

@@ -17,6 +17,8 @@
 
 #include <datasrc/client.h>
 
+#include <dns/name.h>
+
 namespace isc {
 namespace datasrc {
 
@@ -218,8 +220,12 @@ public:
          * \param zone_id The zone ID which was returned from
          *     DatabaseAccessor::getZone and which will be passed to further
          *     calls to the database.
+         * \param origin The name of the origin of this zone. It could query
+         *     it from database, but as the DatabaseClient just searched for
+         *     the zone using the name, it should have it.
          */
-        Finder(boost::shared_ptr<DatabaseAccessor> database, int zone_id);
+        Finder(boost::shared_ptr<DatabaseAccessor> database, int zone_id,
+               const isc::dns::Name& origin);
         // The following three methods are just implementations of inherited
         // ZoneFinder's pure virtual methods.
         virtual isc::dns::Name getOrigin() const;
@@ -290,6 +296,48 @@ public:
     private:
         boost::shared_ptr<DatabaseAccessor> database_;
         const int zone_id_;
+        const isc::dns::Name origin_;
+        /**
+         * \brief Searches database for an RRset
+         *
+         * This method scans RRs of single domain specified by name and finds
+         * RRset with given type or any of redirection RRsets that are
+         * requested.
+         *
+         * This function is used internally by find(), because this part is
+         * called multiple times with slightly different parameters.
+         *
+         * \param name Which domain name should be scanned.
+         * \param type The RRType which is requested. This can be NULL, in
+         *     which case the method will look for the redirections only.
+         * \param want_cname If this is true, CNAME redirection may be returned
+         *     instead of the RRset with given type. If there's CNAME and
+         *     something else or the CNAME has multiple RRs, it throws
+         *     DataSourceError.
+         * \param want_dname If this is true, DNAME redirection may be returned
+         *     instead. This is with type = NULL only and is not checked in
+         *     other circumstances. If the DNAME has multiple RRs, it throws
+         *     DataSourceError.
+         * \param want_ns This allows redirection by NS to be returned. If
+         *     any other data is met as well, DataSourceError is thrown.
+         * \note It may happen that some of the above error conditions are not
+         *     detected in some circumstances. The goal here is not to validate
+         *     the domain in DB, but to avoid bad behaviour resulting from
+         *     broken data.
+         * \return First part of the result tells if the domain contains any
+         *     RRs. This can be used to decide between NXDOMAIN and NXRRSET.
+         *     The second part is the RRset found (if any) with any relevant
+         *     signatures attached to it.
+         * \todo This interface doesn't look very elegant. Any better idea
+         *     would be nice.
+         */
+        std::pair<bool, isc::dns::RRsetPtr> getRRset(const isc::dns::Name&
+                                                     name,
+                                                     const isc::dns::RRType*
+                                                     type,
+                                                     bool want_cname,
+                                                     bool want_dname,
+                                                     bool want_ns);
     };
     /**
      * \brief Find a zone in the database

+ 14 - 0
src/lib/datasrc/datasrc_messages.mes

@@ -90,6 +90,20 @@ most likely points to a logic error in the code, and can be considered a bug.
 The current search is aborted. Specific information about the exception is
 printed in this error message.
 
+% DATASRC_DATABASE_FOUND_DELEGATION Found delegation at %2 in %1
+When searching for a domain, the program met a delegation to a different zone
+at the given domain name. It will return that one instead.
+
+% DATASRC_DATABASE_FOUND_DELEGATION_EXACT Found delegation at %2 (exact match) in %1
+The program found the domain requested, but it is a delegation point to a
+different zone, therefore it is not authoritative for this domain name.
+It will return the NS record instead.
+
+% DATASRC_DATABASE_FOUND_DNAME Found DNAME at %2 in %1
+When searching for a domain, the program met a DNAME redirection to a different
+place in the domain space at the given domain name. It will return that one
+instead.
+
 % DATASRC_DATABASE_FOUND_NXDOMAIN search in datasource %1 resulted in NXDOMAIN for %2/%3/%4
 The data returned by the database backend did not contain any data for the given
 domain name, class and type.

+ 310 - 116
src/lib/datasrc/tests/database_unittest.cc

@@ -263,6 +263,46 @@ private:
         addRecord("A", "3600", "", "192.0.2.1");
         addRecord("RRSIG", "3600", "TXT", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
         addCurName("badsigtype.example.org.");
+
+        // Data for testing delegation (with NS and DNAME)
+        addRecord("NS", "3600", "", "ns.example.com.");
+        addRecord("NS", "3600", "", "ns.delegation.example.org.");
+        addRecord("RRSIG", "3600", "", "NS 5 3 3600 20000101000000 "
+                  "20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addCurName("delegation.example.org.");
+        addRecord("A", "3600", "", "192.0.2.1");
+        addCurName("ns.delegation.example.org.");
+        addRecord("A", "3600", "", "192.0.2.1");
+        addCurName("deep.below.delegation.example.org.");
+
+        addRecord("A", "3600", "", "192.0.2.1");
+        addRecord("DNAME", "3600", "", "dname.example.com.");
+        addRecord("RRSIG", "3600", "", "DNAME 5 3 3600 20000101000000 "
+                  "20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addCurName("dname.example.org.");
+        addRecord("A", "3600", "", "192.0.2.1");
+        addCurName("below.dname.example.org.");
+
+        // Broken NS
+        addRecord("A", "3600", "", "192.0.2.1");
+        addRecord("NS", "3600", "", "ns.example.com.");
+        addCurName("brokenns1.example.org.");
+        addRecord("NS", "3600", "", "ns.example.com.");
+        addRecord("A", "3600", "", "192.0.2.1");
+        addCurName("brokenns2.example.org.");
+
+        // Now double DNAME, to test failure mode
+        addRecord("DNAME", "3600", "", "dname1.example.com.");
+        addRecord("DNAME", "3600", "", "dname2.example.com.");
+        addCurName("baddname.example.org.");
+
+        // Put some data into apex (including NS) so we can check our NS
+        // doesn't break anything
+        addRecord("NS", "3600", "", "ns.example.com.");
+        addRecord("A", "3600", "", "192.0.2.1");
+        addRecord("RRSIG", "3600", "", "NS 5 3 3600 20000101000000 "
+                  "20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addCurName("example.org.");
     }
 };
 
@@ -298,6 +338,21 @@ public:
         EXPECT_EQ(42, finder->zone_id());
         EXPECT_EQ(current_database_, &finder->database());
     }
+
+    shared_ptr<DatabaseClient::Finder> getFinder() {
+        DataSourceClient::FindResult zone(
+            client_->findZone(Name("example.org")));
+        EXPECT_EQ(result::SUCCESS, zone.code);
+        shared_ptr<DatabaseClient::Finder> finder(
+            dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
+        EXPECT_EQ(42, finder->zone_id());
+        EXPECT_FALSE(current_database_->searchRunning());
+
+        return (finder);
+    }
+
+    std::vector<std::string> expected_rdatas_;
+    std::vector<std::string> expected_sig_rdatas_;
 };
 
 TEST_F(DatabaseClientTest, zoneNotFound) {
@@ -352,20 +407,24 @@ doFindTest(shared_ptr<DatabaseClient::Finder> finder,
            const isc::dns::RRType& expected_type,
            const isc::dns::RRTTL expected_ttl,
            ZoneFinder::Result expected_result,
-           const std::vector<std::string>& expected_rdatas,
-           const std::vector<std::string>& expected_sig_rdatas)
+           const std::vector<std::string>& expected_rdatas_,
+           const std::vector<std::string>& expected_sig_rdatas_,
+           const isc::dns::Name& expected_name = isc::dns::Name::ROOT_NAME())
 {
+    SCOPED_TRACE("doFindTest " + name.toText() + " " + type.toText());
     ZoneFinder::FindResult result =
         finder->find(name, type, NULL, ZoneFinder::FIND_DEFAULT);
     ASSERT_EQ(expected_result, result.code) << name << " " << type;
-    if (expected_rdatas.size() > 0) {
-        checkRRset(result.rrset, name, finder->getClass(),
-                   expected_type, expected_ttl, expected_rdatas);
-
-        if (expected_sig_rdatas.size() > 0) {
-            checkRRset(result.rrset->getRRsig(), name,
-                       finder->getClass(), isc::dns::RRType::RRSIG(),
-                       expected_ttl, expected_sig_rdatas);
+    if (expected_rdatas_.size() > 0) {
+        checkRRset(result.rrset, expected_name != Name(".") ? expected_name :
+                   name, finder->getClass(), expected_type, expected_ttl,
+                   expected_rdatas_);
+
+        if (expected_sig_rdatas_.size() > 0) {
+            checkRRset(result.rrset->getRRsig(), expected_name != Name(".") ?
+                       expected_name : name, finder->getClass(),
+                       isc::dns::RRType::RRSIG(), expected_ttl,
+                       expected_sig_rdatas_);
         } else {
             EXPECT_EQ(isc::dns::RRsetPtr(), result.rrset->getRRsig());
         }
@@ -376,227 +435,220 @@ doFindTest(shared_ptr<DatabaseClient::Finder> finder,
 } // end anonymous namespace
 
 TEST_F(DatabaseClientTest, find) {
-    DataSourceClient::FindResult zone(client_->findZone(Name("example.org")));
-    ASSERT_EQ(result::SUCCESS, zone.code);
-    shared_ptr<DatabaseClient::Finder> finder(
-        dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
-    EXPECT_EQ(42, finder->zone_id());
-    EXPECT_FALSE(current_database_->searchRunning());
-    std::vector<std::string> expected_rdatas;
-    std::vector<std::string> expected_sig_rdatas;
+    shared_ptr<DatabaseClient::Finder> finder(getFinder());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("192.0.2.1");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
     doFindTest(finder, isc::dns::Name("www.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::A(),
                isc::dns::RRTTL(3600),
                ZoneFinder::SUCCESS,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("192.0.2.1");
-    expected_rdatas.push_back("192.0.2.2");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_rdatas_.push_back("192.0.2.2");
     doFindTest(finder, isc::dns::Name("www2.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::A(),
                isc::dns::RRTTL(3600),
                ZoneFinder::SUCCESS,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("2001:db8::1");
-    expected_rdatas.push_back("2001:db8::2");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("2001:db8::1");
+    expected_rdatas_.push_back("2001:db8::2");
     doFindTest(finder, isc::dns::Name("www.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
                isc::dns::RRTTL(3600),
                ZoneFinder::SUCCESS,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
     doFindTest(finder, isc::dns::Name("www.example.org."),
                isc::dns::RRType::TXT(), isc::dns::RRType::TXT(),
                isc::dns::RRTTL(3600),
                ZoneFinder::NXRRSET,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("www.example.org.");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("www.example.org.");
     doFindTest(finder, isc::dns::Name("cname.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::CNAME(),
                isc::dns::RRTTL(3600),
                ZoneFinder::CNAME,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("www.example.org.");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("www.example.org.");
     doFindTest(finder, isc::dns::Name("cname.example.org."),
                isc::dns::RRType::CNAME(), isc::dns::RRType::CNAME(),
                isc::dns::RRTTL(3600),
                ZoneFinder::SUCCESS,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
     doFindTest(finder, isc::dns::Name("doesnotexist.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::A(),
                isc::dns::RRTTL(3600),
                ZoneFinder::NXDOMAIN,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("192.0.2.1");
-    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
-    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
     doFindTest(finder, isc::dns::Name("signed1.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::A(),
                isc::dns::RRTTL(3600),
                ZoneFinder::SUCCESS,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("2001:db8::1");
-    expected_rdatas.push_back("2001:db8::2");
-    expected_sig_rdatas.push_back("AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("2001:db8::1");
+    expected_rdatas_.push_back("2001:db8::2");
+    expected_sig_rdatas_.push_back("AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
     doFindTest(finder, isc::dns::Name("signed1.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
                isc::dns::RRTTL(3600),
                ZoneFinder::SUCCESS,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
     doFindTest(finder, isc::dns::Name("signed1.example.org."),
                isc::dns::RRType::TXT(), isc::dns::RRType::TXT(),
                isc::dns::RRTTL(3600),
                ZoneFinder::NXRRSET,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("www.example.org.");
-    expected_sig_rdatas.push_back("CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("www.example.org.");
+    expected_sig_rdatas_.push_back("CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
     doFindTest(finder, isc::dns::Name("signedcname1.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::CNAME(),
                isc::dns::RRTTL(3600),
                ZoneFinder::CNAME,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("192.0.2.1");
-    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
-    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
     doFindTest(finder, isc::dns::Name("signed2.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::A(),
                isc::dns::RRTTL(3600),
                ZoneFinder::SUCCESS,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("2001:db8::2");
-    expected_rdatas.push_back("2001:db8::1");
-    expected_sig_rdatas.push_back("AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("2001:db8::2");
+    expected_rdatas_.push_back("2001:db8::1");
+    expected_sig_rdatas_.push_back("AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
     doFindTest(finder, isc::dns::Name("signed2.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
                isc::dns::RRTTL(3600),
                ZoneFinder::SUCCESS,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
     doFindTest(finder, isc::dns::Name("signed2.example.org."),
                isc::dns::RRType::TXT(), isc::dns::RRType::TXT(),
                isc::dns::RRTTL(3600),
                ZoneFinder::NXRRSET,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("www.example.org.");
-    expected_sig_rdatas.push_back("CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("www.example.org.");
+    expected_sig_rdatas_.push_back("CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
     doFindTest(finder, isc::dns::Name("signedcname2.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::CNAME(),
                isc::dns::RRTTL(3600),
                ZoneFinder::CNAME,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("192.0.2.1");
-    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
     doFindTest(finder, isc::dns::Name("acnamesig1.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::A(),
                isc::dns::RRTTL(3600),
                ZoneFinder::SUCCESS,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("192.0.2.1");
-    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
     doFindTest(finder, isc::dns::Name("acnamesig2.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::A(),
                isc::dns::RRTTL(3600),
                ZoneFinder::SUCCESS,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("192.0.2.1");
-    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
     doFindTest(finder, isc::dns::Name("acnamesig3.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::A(),
                isc::dns::RRTTL(3600),
                ZoneFinder::SUCCESS,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("192.0.2.1");
-    expected_rdatas.push_back("192.0.2.2");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_rdatas_.push_back("192.0.2.2");
     doFindTest(finder, isc::dns::Name("ttldiff1.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::A(),
                isc::dns::RRTTL(360),
                ZoneFinder::SUCCESS,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("192.0.2.1");
-    expected_rdatas.push_back("192.0.2.2");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_rdatas_.push_back("192.0.2.2");
     doFindTest(finder, isc::dns::Name("ttldiff2.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::A(),
                isc::dns::RRTTL(360),
                ZoneFinder::SUCCESS,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 
 
@@ -672,16 +724,158 @@ TEST_F(DatabaseClientTest, find) {
     // This RRSIG has the wrong sigtype field, which should be
     // an error if we decide to keep using that field
     // Right now the field is ignored, so it does not error
-    expected_rdatas.clear();
-    expected_sig_rdatas.clear();
-    expected_rdatas.push_back("192.0.2.1");
-    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
     doFindTest(finder, isc::dns::Name("badsigtype.example.org."),
                isc::dns::RRType::A(), isc::dns::RRType::A(),
                isc::dns::RRTTL(3600),
                ZoneFinder::SUCCESS,
-               expected_rdatas, expected_sig_rdatas);
+               expected_rdatas_, expected_sig_rdatas_);
     EXPECT_FALSE(current_database_->searchRunning());
 }
 
+TEST_F(DatabaseClientTest, findDelegation) {
+    shared_ptr<DatabaseClient::Finder> finder(getFinder());
+
+    // The apex should not be considered delegation point and we can access
+    // data
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    doFindTest(finder, isc::dns::Name("example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::A(),
+               isc::dns::RRTTL(3600), ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("ns.example.com.");
+    expected_sig_rdatas_.push_back("NS 5 3 3600 20000101000000 20000201000000 "
+                                  "12345 example.org. FAKEFAKEFAKE");
+    doFindTest(finder, isc::dns::Name("example.org."),
+               isc::dns::RRType::NS(), isc::dns::RRType::NS(),
+               isc::dns::RRTTL(3600), ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    // Check when we ask for something below delegation point, we get the NS
+    // (Both when the RRset there exists and doesn't)
+    expected_rdatas_.clear();
+    expected_sig_rdatas_.clear();
+    expected_rdatas_.push_back("ns.example.com.");
+    expected_rdatas_.push_back("ns.delegation.example.org.");
+    expected_sig_rdatas_.push_back("NS 5 3 3600 20000101000000 20000201000000 "
+                                  "12345 example.org. FAKEFAKEFAKE");
+    doFindTest(finder, isc::dns::Name("ns.delegation.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::NS(),
+               isc::dns::RRTTL(3600), ZoneFinder::DELEGATION, expected_rdatas_,
+               expected_sig_rdatas_,
+               isc::dns::Name("delegation.example.org."));
+    EXPECT_FALSE(current_database_->searchRunning());
+    doFindTest(finder, isc::dns::Name("ns.delegation.example.org."),
+               isc::dns::RRType::AAAA(), isc::dns::RRType::NS(),
+               isc::dns::RRTTL(3600), ZoneFinder::DELEGATION, expected_rdatas_,
+               expected_sig_rdatas_,
+               isc::dns::Name("delegation.example.org."));
+    doFindTest(finder, isc::dns::Name("deep.below.delegation.example.org."),
+               isc::dns::RRType::AAAA(), isc::dns::RRType::NS(),
+               isc::dns::RRTTL(3600), ZoneFinder::DELEGATION, expected_rdatas_,
+               expected_sig_rdatas_,
+               isc::dns::Name("delegation.example.org."));
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    // Even when we check directly at the delegation point, we should get
+    // the NS
+    doFindTest(finder, isc::dns::Name("delegation.example.org."),
+               isc::dns::RRType::AAAA(), isc::dns::RRType::NS(),
+               isc::dns::RRTTL(3600), ZoneFinder::DELEGATION, expected_rdatas_,
+               expected_sig_rdatas_);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    // And when we ask direcly for the NS, we should still get delegation
+    doFindTest(finder, isc::dns::Name("delegation.example.org."),
+               isc::dns::RRType::NS(), isc::dns::RRType::NS(),
+               isc::dns::RRTTL(3600), ZoneFinder::DELEGATION, expected_rdatas_,
+               expected_sig_rdatas_);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    // Now test delegation. If it is below the delegation point, we should get
+    // the DNAME (the one with data under DNAME is invalid zone, but we test
+    // the behaviour anyway just to make sure)
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("dname.example.com.");
+    expected_sig_rdatas_.clear();
+    expected_sig_rdatas_.push_back("DNAME 5 3 3600 20000101000000 "
+                                  "20000201000000 12345 example.org. "
+                                  "FAKEFAKEFAKE");
+    doFindTest(finder, isc::dns::Name("below.dname.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::DNAME(),
+               isc::dns::RRTTL(3600), ZoneFinder::DNAME, expected_rdatas_,
+               expected_sig_rdatas_, isc::dns::Name("dname.example.org."));
+    EXPECT_FALSE(current_database_->searchRunning());
+    doFindTest(finder, isc::dns::Name("below.dname.example.org."),
+               isc::dns::RRType::AAAA(), isc::dns::RRType::DNAME(),
+               isc::dns::RRTTL(3600), ZoneFinder::DNAME, expected_rdatas_,
+               expected_sig_rdatas_, isc::dns::Name("dname.example.org."));
+    EXPECT_FALSE(current_database_->searchRunning());
+    doFindTest(finder, isc::dns::Name("really.deep.below.dname.example.org."),
+               isc::dns::RRType::AAAA(), isc::dns::RRType::DNAME(),
+               isc::dns::RRTTL(3600), ZoneFinder::DNAME, expected_rdatas_,
+               expected_sig_rdatas_, isc::dns::Name("dname.example.org."));
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    // Asking direcly for DNAME should give SUCCESS
+    doFindTest(finder, isc::dns::Name("dname.example.org."),
+               isc::dns::RRType::DNAME(), isc::dns::RRType::DNAME(),
+               isc::dns::RRTTL(3600), ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_);
+
+    // But we don't delegate at DNAME point
+    expected_rdatas_.clear();
+    expected_rdatas_.push_back("192.0.2.1");
+    expected_sig_rdatas_.clear();
+    doFindTest(finder, isc::dns::Name("dname.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::A(),
+               isc::dns::RRTTL(3600), ZoneFinder::SUCCESS, expected_rdatas_,
+               expected_sig_rdatas_);
+    EXPECT_FALSE(current_database_->searchRunning());
+    expected_rdatas_.clear();
+    doFindTest(finder, isc::dns::Name("dname.example.org."),
+               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
+               isc::dns::RRTTL(3600), ZoneFinder::NXRRSET, expected_rdatas_,
+               expected_sig_rdatas_);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    // This is broken dname, it contains two targets
+    EXPECT_THROW(finder->find(isc::dns::Name("below.baddname.example.org."),
+                              isc::dns::RRType::A(), NULL,
+                              ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    // Broken NS - it lives together with something else
+    EXPECT_FALSE(current_database_->searchRunning());
+    EXPECT_THROW(finder->find(isc::dns::Name("brokenns1.example.org."),
+                              isc::dns::RRType::A(), NULL,
+                              ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+    EXPECT_FALSE(current_database_->searchRunning());
+    EXPECT_THROW(finder->find(isc::dns::Name("brokenns2.example.org."),
+                              isc::dns::RRType::A(), NULL,
+                              ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+    EXPECT_FALSE(current_database_->searchRunning());
+}
+
+TEST_F(DatabaseClientTest, getOrigin) {
+    DataSourceClient::FindResult zone(client_->findZone(Name("example.org")));
+    ASSERT_EQ(result::SUCCESS, zone.code);
+    shared_ptr<DatabaseClient::Finder> finder(
+        dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
+    EXPECT_EQ(42, finder->zone_id());
+    EXPECT_EQ(isc::dns::Name("example.org"), finder->getOrigin());
+}
+
 }