BIND 10 trac1061, updated. 823e0fcf308c7f3fc88ba48070e12bd995e75392 [trac1061] Implement SQLite3Connection::getZone

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Aug 3 09:15:12 UTC 2011


The branch, trac1061 has been updated
       via  823e0fcf308c7f3fc88ba48070e12bd995e75392 (commit)
       via  608d45610e9f499fb43d2e52eba461d489a7d45f (commit)
       via  e76dc86b0a01a54dab56cbf8552bd0c5fbb5b461 (commit)
      from  be9d5fe994e6a086a951e432d56e7de2af3cfd09 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 823e0fcf308c7f3fc88ba48070e12bd995e75392
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Wed Aug 3 11:14:41 2011 +0200

    [trac1061] Implement SQLite3Connection::getZone

commit 608d45610e9f499fb43d2e52eba461d489a7d45f
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Wed Aug 3 10:58:47 2011 +0200

    [trac1061] Tests for SQLite3Connection::getZone
    
    These are not copied, as this method was not public in the original
    implementation. The constructor got a new parameter, the RR class, so it
    knows what to query from the DB.

commit e76dc86b0a01a54dab56cbf8552bd0c5fbb5b461
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Tue Aug 2 22:28:14 2011 +0200

    [trac1061] (Co|De)structor of SQLite3Connection
    
    Most of the code is slightly modified copy-paste from the
    Sqlite3DataSource. No documentation or log messages and the getZone
    method is dummy. But it compiles and provides some kind of frame for the
    rest.

-----------------------------------------------------------------------

Summary of changes:
 src/lib/datasrc/datasrc_messages.mes               |    7 +
 src/lib/datasrc/sqlite3_connection.cc              |  308 ++++++++++++++++++++
 src/lib/datasrc/sqlite3_connection.h               |   34 ++-
 src/lib/datasrc/tests/Makefile.am                  |    1 +
 .../datasrc/tests/sqlite3_connection_unittest.cc   |  116 ++++++++
 5 files changed, 456 insertions(+), 10 deletions(-)
 create mode 100644 src/lib/datasrc/tests/sqlite3_connection_unittest.cc

-----------------------------------------------------------------------
diff --git a/src/lib/datasrc/datasrc_messages.mes b/src/lib/datasrc/datasrc_messages.mes
index 3dc69e0..a6f7837 100644
--- a/src/lib/datasrc/datasrc_messages.mes
+++ b/src/lib/datasrc/datasrc_messages.mes
@@ -497,3 +497,10 @@ data source.
 This indicates a programming error. An internal task of unknown type was
 generated.
 
+% DATASRC_SQLITE_NEWCONN TODO
+
+% DATASRC_SQLITE_DROPCONN TODO
+
+% DATASRC_SQLITE_CONNOPEN TODO
+
+% DATASRC_SQLITE_CONNCLOSE TODO
diff --git a/src/lib/datasrc/sqlite3_connection.cc b/src/lib/datasrc/sqlite3_connection.cc
index e8c2509..e850db4 100644
--- a/src/lib/datasrc/sqlite3_connection.cc
+++ b/src/lib/datasrc/sqlite3_connection.cc
@@ -12,3 +12,311 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <sqlite3.h>
+
+#include <datasrc/sqlite3_connection.h>
+#include <datasrc/logger.h>
+#include <datasrc/data_source.h>
+
+namespace isc {
+namespace datasrc {
+
+struct SQLite3Parameters {
+    SQLite3Parameters() :
+        db_(NULL), version_(-1),
+        q_zone_(NULL) /*, q_record_(NULL), q_addrs_(NULL), q_referral_(NULL),
+        q_any_(NULL), q_count_(NULL), q_previous_(NULL), q_nsec3_(NULL),
+        q_prevnsec3_(NULL) */
+    {}
+    sqlite3* db_;
+    int version_;
+    sqlite3_stmt* q_zone_;
+    /*
+    TODO: Yet unneeded statements
+    sqlite3_stmt* q_record_;
+    sqlite3_stmt* q_addrs_;
+    sqlite3_stmt* q_referral_;
+    sqlite3_stmt* q_any_;
+    sqlite3_stmt* q_count_;
+    sqlite3_stmt* q_previous_;
+    sqlite3_stmt* q_nsec3_;
+    sqlite3_stmt* q_prevnsec3_;
+    */
+};
+
+SQLite3Connection::SQLite3Connection(const isc::data::ConstElementPtr&
+                                     config,
+                                     const isc::dns::RRClass& rrclass) :
+    dbparameters_(new SQLite3Parameters),
+    class_(rrclass.toText())
+{
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_NEWCONN);
+
+    if (config && config->contains("database_file")) {
+        open(config->get("database_file")->stringValue());
+    } else {
+        isc_throw(DataSourceError, "No SQLite database file specified");
+    }
+}
+
+namespace {
+
+// This is a helper class to initialize a Sqlite3 DB safely.  An object of
+// this class encapsulates all temporary resources that are necessary for
+// the initialization, and release them in the destructor.  Once everything
+// is properly initialized, the move() method moves the allocated resources
+// to the main object in an exception free manner.  This way, the main code
+// for the initialization can be exception safe, and can provide the strong
+// exception guarantee.
+class Initializer {
+public:
+    ~Initializer() {
+        if (params_.q_zone_ != NULL) {
+            sqlite3_finalize(params_.q_zone_);
+        }
+        /*
+        if (params_.q_record_ != NULL) {
+            sqlite3_finalize(params_.q_record_);
+        }
+        if (params_.q_addrs_ != NULL) {
+            sqlite3_finalize(params_.q_addrs_);
+        }
+        if (params_.q_referral_ != NULL) {
+            sqlite3_finalize(params_.q_referral_);
+        }
+        if (params_.q_any_ != NULL) {
+            sqlite3_finalize(params_.q_any_);
+        }
+        if (params_.q_count_ != NULL) {
+            sqlite3_finalize(params_.q_count_);
+        }
+        if (params_.q_previous_ != NULL) {
+            sqlite3_finalize(params_.q_previous_);
+        }
+        if (params_.q_nsec3_ != NULL) {
+            sqlite3_finalize(params_.q_nsec3_);
+        }
+        if (params_.q_prevnsec3_ != NULL) {
+            sqlite3_finalize(params_.q_prevnsec3_);
+        }
+        */
+        if (params_.db_ != NULL) {
+            sqlite3_close(params_.db_);
+        }
+    }
+    void move(SQLite3Parameters* dst) {
+        *dst = params_;
+        params_ = SQLite3Parameters(); // clear everything
+    }
+    SQLite3Parameters params_;
+};
+
+const char* const SCHEMA_LIST[] = {
+    "CREATE TABLE schema_version (version INTEGER NOT NULL)",
+    "INSERT INTO schema_version VALUES (1)",
+    "CREATE TABLE zones (id INTEGER PRIMARY KEY, "
+    "name STRING NOT NULL COLLATE NOCASE, "
+    "rdclass STRING NOT NULL COLLATE NOCASE DEFAULT 'IN', "
+    "dnssec BOOLEAN NOT NULL DEFAULT 0)",
+    "CREATE INDEX zones_byname ON zones (name)",
+    "CREATE TABLE records (id INTEGER PRIMARY KEY, "
+    "zone_id INTEGER NOT NULL, name STRING NOT NULL COLLATE NOCASE, "
+    "rname STRING NOT NULL COLLATE NOCASE, ttl INTEGER NOT NULL, "
+    "rdtype STRING NOT NULL COLLATE NOCASE, sigtype STRING COLLATE NOCASE, "
+    "rdata STRING NOT NULL)",
+    "CREATE INDEX records_byname ON records (name)",
+    "CREATE INDEX records_byrname ON records (rname)",
+    "CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, zone_id INTEGER NOT NULL, "
+    "hash STRING NOT NULL COLLATE NOCASE, "
+    "owner STRING NOT NULL COLLATE NOCASE, "
+    "ttl INTEGER NOT NULL, rdtype STRING NOT NULL COLLATE NOCASE, "
+    "rdata STRING NOT NULL)",
+    "CREATE INDEX nsec3_byhash ON nsec3 (hash)",
+    NULL
+};
+
+const char* const q_zone_str = "SELECT id FROM zones WHERE name=?1 AND rdclass = ?2";
+
+/* TODO: Prune the statements, not everything will be needed maybe?
+const char* const q_record_str = "SELECT rdtype, ttl, sigtype, rdata "
+    "FROM records WHERE zone_id=?1 AND name=?2 AND "
+    "((rdtype=?3 OR sigtype=?3) OR "
+    "(rdtype='CNAME' OR sigtype='CNAME') OR "
+    "(rdtype='NS' OR sigtype='NS'))";
+
+const char* const q_addrs_str = "SELECT rdtype, ttl, sigtype, rdata "
+    "FROM records WHERE zone_id=?1 AND name=?2 AND "
+    "(rdtype='A' OR sigtype='A' OR rdtype='AAAA' OR sigtype='AAAA')";
+
+const char* const q_referral_str = "SELECT rdtype, ttl, sigtype, rdata FROM "
+    "records WHERE zone_id=?1 AND name=?2 AND"
+    "(rdtype='NS' OR sigtype='NS' OR rdtype='DS' OR sigtype='DS' OR "
+    "rdtype='DNAME' OR sigtype='DNAME')";
+
+const char* const q_any_str = "SELECT rdtype, ttl, sigtype, rdata "
+    "FROM records WHERE zone_id=?1 AND name=?2";
+
+const char* const q_count_str = "SELECT COUNT(*) FROM records "
+    "WHERE zone_id=?1 AND rname LIKE (?2 || '%');";
+
+const char* const q_previous_str = "SELECT name FROM records "
+    "WHERE zone_id=?1 AND rdtype = 'NSEC' AND "
+    "rname < $2 ORDER BY rname DESC LIMIT 1";
+
+const char* const q_nsec3_str = "SELECT rdtype, ttl, rdata FROM nsec3 "
+    "WHERE zone_id = ?1 AND hash = $2";
+
+const char* const q_prevnsec3_str = "SELECT hash FROM nsec3 "
+    "WHERE zone_id = ?1 AND hash <= $2 ORDER BY hash DESC LIMIT 1";
+    */
+
+sqlite3_stmt*
+prepare(sqlite3* const db, const char* const statement) {
+    sqlite3_stmt* prepared = NULL;
+    if (sqlite3_prepare_v2(db, statement, -1, &prepared, NULL) != SQLITE_OK) {
+        isc_throw(SQLite3Error, "Could not prepare SQLite statement: " <<
+                  statement);
+    }
+    return (prepared);
+}
+
+void
+checkAndSetupSchema(Initializer* initializer) {
+    sqlite3* const db = initializer->params_.db_;
+
+    sqlite3_stmt* prepared = NULL;
+    if (sqlite3_prepare_v2(db, "SELECT version FROM schema_version", -1,
+                           &prepared, NULL) == SQLITE_OK &&
+        sqlite3_step(prepared) == SQLITE_ROW) {
+        initializer->params_.version_ = sqlite3_column_int(prepared, 0);
+        sqlite3_finalize(prepared);
+    } else {
+        logger.info(DATASRC_SQLITE_SETUP);
+        if (prepared != NULL) {
+            sqlite3_finalize(prepared);
+        }
+        for (int i = 0; SCHEMA_LIST[i] != NULL; ++i) {
+            if (sqlite3_exec(db, SCHEMA_LIST[i], NULL, NULL, NULL) !=
+                SQLITE_OK) {
+                isc_throw(SQLite3Error,
+                          "Failed to set up schema " << SCHEMA_LIST[i]);
+            }
+        }
+    }
+
+    initializer->params_.q_zone_ = prepare(db, q_zone_str);
+    /* TODO: Yet unneeded statements
+    initializer->params_.q_record_ = prepare(db, q_record_str);
+    initializer->params_.q_addrs_ = prepare(db, q_addrs_str);
+    initializer->params_.q_referral_ = prepare(db, q_referral_str);
+    initializer->params_.q_any_ = prepare(db, q_any_str);
+    initializer->params_.q_count_ = prepare(db, q_count_str);
+    initializer->params_.q_previous_ = prepare(db, q_previous_str);
+    initializer->params_.q_nsec3_ = prepare(db, q_nsec3_str);
+    initializer->params_.q_prevnsec3_ = prepare(db, q_prevnsec3_str);
+    */
+}
+
+}
+
+void
+SQLite3Connection::open(const std::string& name) {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CONNOPEN).arg(name);
+    if (dbparameters_->db_ != NULL) {
+        // There shouldn't be a way to trigger this anyway
+        isc_throw(DataSourceError, "Duplicate SQLite open with " << name);
+    }
+
+    Initializer initializer;
+
+    if (sqlite3_open(name.c_str(), &initializer.params_.db_) != 0) {
+        isc_throw(SQLite3Error, "Cannot open SQLite database file: " << name);
+    }
+
+    checkAndSetupSchema(&initializer);
+    initializer.move(dbparameters_);
+}
+
+SQLite3Connection::~ SQLite3Connection() {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_DROPCONN);
+    if (dbparameters_->db_ != NULL) {
+        close();
+    }
+    delete dbparameters_;
+}
+
+void
+SQLite3Connection::close(void) {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CONNCLOSE);
+    if (dbparameters_->db_ == NULL) {
+        isc_throw(DataSourceError,
+                  "SQLite data source is being closed before open");
+    }
+
+    // XXX: sqlite3_finalize() could fail.  What should we do in that case?
+    sqlite3_finalize(dbparameters_->q_zone_);
+    dbparameters_->q_zone_ = NULL;
+
+    /* TODO: Once they are needed or not, uncomment or drop
+    sqlite3_finalize(dbparameters->q_record_);
+    dbparameters->q_record_ = NULL;
+
+    sqlite3_finalize(dbparameters->q_addrs_);
+    dbparameters->q_addrs_ = NULL;
+
+    sqlite3_finalize(dbparameters->q_referral_);
+    dbparameters->q_referral_ = NULL;
+
+    sqlite3_finalize(dbparameters->q_any_);
+    dbparameters->q_any_ = NULL;
+
+    sqlite3_finalize(dbparameters->q_count_);
+    dbparameters->q_count_ = NULL;
+
+    sqlite3_finalize(dbparameters->q_previous_);
+    dbparameters->q_previous_ = NULL;
+
+    sqlite3_finalize(dbparameters->q_prevnsec3_);
+    dbparameters->q_prevnsec3_ = NULL;
+
+    sqlite3_finalize(dbparameters->q_nsec3_);
+    dbparameters->q_nsec3_ = NULL;
+    */
+
+    sqlite3_close(dbparameters_->db_);
+    dbparameters_->db_ = NULL;
+}
+
+std::pair<bool, int>
+SQLite3Connection::getZone(const isc::dns::Name& name) const {
+    int rc;
+
+    sqlite3_reset(dbparameters_->q_zone_);
+    rc = sqlite3_bind_text(dbparameters_->q_zone_, 1, name.toText().c_str(),
+                           -1, SQLITE_STATIC);
+    if (rc != SQLITE_OK) {
+        isc_throw(SQLite3Error, "Could not bind " << name <<
+                  " to SQL statement (zone)");
+    }
+    rc = sqlite3_bind_text(dbparameters_->q_zone_, 2, class_.c_str(), -1,
+                           SQLITE_STATIC);
+    if (rc != SQLITE_OK) {
+        isc_throw(SQLite3Error, "Could not bind " << class_ <<
+                  " to SQL statement (zone)");
+    }
+
+    rc = sqlite3_step(dbparameters_->q_zone_);
+    std::pair<bool, int> result;
+    if (rc == SQLITE_ROW) {
+        result = std::pair<bool, int>(true,
+                                      sqlite3_column_int(dbparameters_->
+                                                         q_zone_, 0));
+    } else {
+        result = std::pair<bool, int>(false, 0);
+    }
+    sqlite3_reset(dbparameters_->q_zone_);
+    return (result);
+}
+
+}
+}
diff --git a/src/lib/datasrc/sqlite3_connection.h b/src/lib/datasrc/sqlite3_connection.h
index e18386c..86ad9c3 100644
--- a/src/lib/datasrc/sqlite3_connection.h
+++ b/src/lib/datasrc/sqlite3_connection.h
@@ -18,23 +18,37 @@
 
 #include <datasrc/database.h>
 
-// TODO Once the whole SQLite3 thing is ported here, move the Sqlite3Error
-// here and remove the header file.
-#include <datasrc/sqlite3_datasrc.h>
+#include <exceptions/exceptions.h>
+#include <cc/data.h>
+
+#include <string>
 
 namespace isc {
+namespace dns {
+class RRClass;
+}
+
 namespace datasrc {
 
-class SQLite3Connection : public DatabaseConnection {
+class SQLite3Error : public Exception {
 public:
-    // TODO Should we simplify this as well and just pass config to the
-    // constructor and be done? (whenever the config would change, we would
-    // recreate new connections)
-    Result init() { return (init(isc::data::ElementPtr())); }
-    Result init(const isc::data::ConstElementPtr& config);
-    Result close();
+    SQLite3Error(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+struct SQLite3Parameters;
 
+class SQLite3Connection : public DatabaseConnection {
+public:
+    SQLite3Connection(const isc::data::ConstElementPtr& config,
+                      const isc::dns::RRClass& rrclass);
+    ~ SQLite3Connection();
     virtual std::pair<bool, int> getZone(const isc::dns::Name& name) const;
+private:
+    SQLite3Parameters* dbparameters_;
+    const std::string class_;
+    void open(const std::string& filename);
+    void close();
 };
 
 }
diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am
index 9cfd0d8..c2e2b5c 100644
--- a/src/lib/datasrc/tests/Makefile.am
+++ b/src/lib/datasrc/tests/Makefile.am
@@ -29,6 +29,7 @@ run_unittests_SOURCES += zonetable_unittest.cc
 run_unittests_SOURCES += memory_datasrc_unittest.cc
 run_unittests_SOURCES += logger_unittest.cc
 run_unittests_SOURCES += database_unittest.cc
+run_unittests_SOURCES += sqlite3_connection_unittest.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)
diff --git a/src/lib/datasrc/tests/sqlite3_connection_unittest.cc b/src/lib/datasrc/tests/sqlite3_connection_unittest.cc
new file mode 100644
index 0000000..3065dfe
--- /dev/null
+++ b/src/lib/datasrc/tests/sqlite3_connection_unittest.cc
@@ -0,0 +1,116 @@
+// Copyright (C) 2011  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.
+
+#include <datasrc/sqlite3_connection.h>
+#include <datasrc/data_source.h>
+
+#include <dns/rrclass.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::datasrc;
+using isc::data::ConstElementPtr;
+using isc::data::Element;
+using isc::dns::RRClass;
+using isc::dns::Name;
+
+namespace {
+// Some test data
+ConstElementPtr SQLITE_DBFILE_EXAMPLE = Element::fromJSON(
+    "{ \"database_file\": \"" TEST_DATA_DIR "/test.sqlite3\"}");
+ConstElementPtr SQLITE_DBFILE_EXAMPLE2 = Element::fromJSON(
+    "{ \"database_file\": \"" TEST_DATA_DIR "/example2.com.sqlite3\"}");
+ConstElementPtr SQLITE_DBFILE_EXAMPLE_ROOT = Element::fromJSON(
+    "{ \"database_file\": \"" TEST_DATA_DIR "/test-root.sqlite3\"}");
+ConstElementPtr SQLITE_DBFILE_BROKENDB = Element::fromJSON(
+    "{ \"database_file\": \"" TEST_DATA_DIR "/brokendb.sqlite3\"}");
+ConstElementPtr SQLITE_DBFILE_MEMORY = Element::fromJSON(
+    "{ \"database_file\": \":memory:\"}");
+
+// The following file must be non existent and must be non"creatable";
+// the sqlite3 library will try to create a new DB file if it doesn't exist,
+// so to test a failure case the create operation should also fail.
+// The "nodir", a non existent directory, is inserted for this purpose.
+ConstElementPtr SQLITE_DBFILE_NOTEXIST = Element::fromJSON(
+    "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}");
+
+// Opening works (the content is tested in different tests)
+TEST(SQLite3Open, common) {
+    EXPECT_NO_THROW(SQLite3Connection conn(SQLITE_DBFILE_EXAMPLE,
+                                           RRClass::IN()));
+}
+
+// Missing config
+TEST(SQLite3Open, noConfig) {
+    EXPECT_THROW(SQLite3Connection conn(Element::fromJSON("{}"),
+                                                          RRClass::IN()),
+                 DataSourceError);
+}
+
+// The file can't be opened
+TEST(SQLite3Open, notExist) {
+    EXPECT_THROW(SQLite3Connection conn(SQLITE_DBFILE_NOTEXIST,
+                                        RRClass::IN()), SQLite3Error);
+}
+
+// It rejects broken DB
+TEST(SQLite3Open, brokenDB) {
+    EXPECT_THROW(SQLite3Connection conn(SQLITE_DBFILE_BROKENDB,
+                                        RRClass::IN()), SQLite3Error);
+}
+
+// Test we can create the schema on the fly
+TEST(SQLite3Open, memoryDB) {
+    EXPECT_NO_THROW(SQLite3Connection conn(SQLITE_DBFILE_MEMORY,
+                                           RRClass::IN()));
+}
+
+// Test fixture for querying the connection
+class SQLite3Conn : public ::testing::Test {
+public:
+    SQLite3Conn() {
+        initConn(SQLITE_DBFILE_EXAMPLE, RRClass::IN());
+    }
+    // So it can be re-created with different data
+    void initConn(const ConstElementPtr& config, const RRClass& rrclass) {
+        conn.reset(new SQLite3Connection(config, rrclass));
+    }
+    // The tested connection
+    std::auto_ptr<SQLite3Connection> conn;
+};
+
+// This zone exists in the data, so it should be found
+TEST_F(SQLite3Conn, getZone) {
+    std::pair<bool, int> result(conn->getZone(Name("example.com")));
+    EXPECT_TRUE(result.first);
+    EXPECT_EQ(1, result.second);
+}
+
+// But it should find only the zone, nothing below it
+TEST_F(SQLite3Conn, subZone) {
+    EXPECT_FALSE(conn->getZone(Name("sub.example.com")).first);
+}
+
+// This zone is not there at all
+TEST_F(SQLite3Conn, noZone) {
+    EXPECT_FALSE(conn->getZone(Name("example.org")).first);
+}
+
+// This zone is there, but in different class
+TEST_F(SQLite3Conn, noClass) {
+    initConn(SQLITE_DBFILE_EXAMPLE, RRClass::CH());
+    EXPECT_FALSE(conn->getZone(Name("example.com")).first);
+}
+
+}




More information about the bind10-changes mailing list