Browse Source

[master] Merge branch 'trac1792' with fixing conflicts.

JINMEI Tatuya 13 years ago
parent
commit
93f11d2a96

+ 28 - 10
src/bin/auth/auth_config.cc

@@ -12,14 +12,6 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <boost/foreach.hpp>
-#include <boost/shared_ptr.hpp>
-
 #include <dns/name.h>
 #include <dns/rrclass.h>
 
@@ -27,6 +19,7 @@
 
 #include <datasrc/memory_datasrc.h>
 #include <datasrc/zonetable.h>
+#include <datasrc/factory.h>
 
 #include <auth/auth_srv.h>
 #include <auth/auth_config.h>
@@ -34,6 +27,15 @@
 
 #include <server_common/portconfig.h>
 
+#include <boost/foreach.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
 using namespace std;
 using namespace isc::dns;
 using namespace isc::data;
@@ -165,10 +167,21 @@ MemoryDatasourceConfig::build(ConstElementPtr config_value) {
             isc_throw(AuthConfigError, "Missing zone file for zone: "
                       << origin_txt);
         }
+
+        // We support the traditional text type and SQLite3 backend.  For the
+        // latter we create a client for the underlying SQLite3 data source,
+        // and build the in-memory zone using an iterator of the underlying
+        // zone.
         ConstElementPtr filetype = zone_config->get("filetype");
         const string filetype_txt = filetype ? filetype->stringValue() :
             "text";
-        if (filetype_txt != "text") {
+        boost::scoped_ptr<DataSourceClientContainer> container;
+        if (filetype_txt == "sqlite3") {
+            container.reset(new DataSourceClientContainer(
+                                "sqlite3",
+                                Element::fromJSON("{\"database_file\": \"" +
+                                                  file_txt + "\"}")));
+        } else if (filetype_txt != "text") {
             isc_throw(AuthConfigError, "Invalid filetype for zone "
                       << origin_txt << ": " << filetype_txt);
         }
@@ -198,7 +211,12 @@ MemoryDatasourceConfig::build(ConstElementPtr config_value) {
          * need the load method to be split into some kind of build and
          * commit/abort parts.
          */
-        zone_finder->load(file_txt);
+        if (filetype_txt == "text") {
+            zone_finder->load(file_txt);
+        } else {
+            zone_finder->load(*container->getInstance().getIterator(
+                                  Name(origin_txt)));
+        }
     }
 }
 

+ 4 - 0
src/bin/auth/tests/Makefile.am

@@ -12,6 +12,9 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 if USE_STATIC_LINK
 AM_LDFLAGS = -static
+# Some test cases cannot work with static link.  To selectively disable such
+# tests we signal it via a definition.
+AM_CPPFLAGS += -DUSE_STATIC_LINK=1
 endif
 
 CLEANFILES = *.gcno *.gcda
@@ -29,6 +32,7 @@ run_unittests_SOURCES += ../auth_config.h ../auth_config.cc
 run_unittests_SOURCES += ../command.h ../command.cc
 run_unittests_SOURCES += ../common.h ../common.cc
 run_unittests_SOURCES += ../statistics.h ../statistics.cc
+run_unittests_SOURCES += datasrc_util.h datasrc_util.cc
 run_unittests_SOURCES += auth_srv_unittest.cc
 run_unittests_SOURCES += config_unittest.cc
 run_unittests_SOURCES += config_syntax_unittest.cc

+ 38 - 4
src/bin/auth/tests/config_unittest.cc

@@ -21,6 +21,7 @@
 
 #include <cc/data.h>
 
+#include <datasrc/data_source.h>
 #include <datasrc/memory_datasrc.h>
 
 #include <xfr/xfrout_client.h>
@@ -29,14 +30,20 @@
 #include <auth/auth_config.h>
 #include <auth/common.h>
 
+#include "datasrc_util.h"
+
 #include <testutils/mockups.h>
 #include <testutils/portconfig.h>
 #include <testutils/socket_request.h>
 
+#include <sstream>
+
+using namespace std;
 using namespace isc::dns;
 using namespace isc::data;
 using namespace isc::datasrc;
 using namespace isc::asiodns;
+using namespace isc::auth::unittest;
 using namespace isc::testutils;
 
 namespace {
@@ -201,17 +208,44 @@ TEST_F(MemoryDatasrcConfigTest, addOneZone) {
         RRType::A())->code);
 }
 
-TEST_F(MemoryDatasrcConfigTest, addOneWithFiletype) {
-    // Until #1792 is completed, only "text" filetype is allowed.
+// This test uses dynamic load of a data source module, and won't work when
+// statically linked.
+TEST_F(MemoryDatasrcConfigTest,
+#ifdef USE_STATIC_LINK
+       DISABLED_addOneWithFiletypeSQLite3
+#else
+       addOneWithFiletypeSQLite3
+#endif
+    )
+{
+    const string test_db = TEST_DATA_BUILDDIR "/auth_test.sqlite3.copied";
+    stringstream ss("example.org. 3600 IN SOA . . 0 0 0 0 0\n");
+    createSQLite3DB(rrclass, Name("example.org"), test_db.c_str(), ss);
+
+    // In-memory with an SQLite3 data source as the backend.
+    parser->build(Element::fromJSON(
+                      "[{\"type\": \"memory\","
+                      "  \"zones\": [{\"origin\": \"example.org\","
+                      "               \"file\": \""
+                      + test_db +  "\","
+                      "               \"filetype\": \"sqlite3\"}]}]"));
+    parser->commit();
+    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
+
+    // Failure case: the specified zone doesn't exist in the DB file.
+    delete parser;
+    parser = createAuthConfigParser(server, "datasources");
     EXPECT_THROW(parser->build(
                      Element::fromJSON(
                          "[{\"type\": \"memory\","
                          "  \"zones\": [{\"origin\": \"example.com\","
                          "               \"file\": \""
-                         TEST_DATA_DIR "/example.zone\","
+                         + test_db +  "\","
                          "               \"filetype\": \"sqlite3\"}]}]")),
-                 AuthConfigError);
+                 DataSourceError);
+}
 
+TEST_F(MemoryDatasrcConfigTest, addOneWithFiletypeText) {
     // Explicitly specifying "text" is okay.
     parser->build(Element::fromJSON(
                       "[{\"type\": \"memory\","

+ 77 - 0
src/bin/auth/tests/datasrc_util.cc

@@ -0,0 +1,77 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <exceptions/exceptions.h>
+
+#include <dns/masterload.h>
+#include <dns/name.h>
+#include <dns/rrclass.h>
+
+#include <cc/data.h>
+
+#include <datasrc/client.h>
+#include <datasrc/zone.h>
+#include <datasrc/factory.h>
+
+#include "datasrc_util.h"
+
+#include <boost/bind.hpp>
+
+#include <istream>
+
+#include <cstdlib>
+
+using namespace std;
+
+using namespace isc::dns;
+using namespace isc::data;
+using namespace isc::datasrc;
+
+namespace isc {
+namespace auth {
+namespace unittest {
+
+namespace {
+void
+addRRset(ZoneUpdaterPtr updater, ConstRRsetPtr rrset) {
+    updater->addRRset(*rrset);
+}
+}
+
+void
+createSQLite3DB(RRClass zclass, const Name& zname,
+                const char* const db_file, istream& rr_stream)
+{
+    // We always begin with an empty template SQLite3 DB file and install
+    // the zone data from the zone file.
+    const char* const install_cmd_prefix = INSTALL_PROG " " TEST_DATA_DIR
+        "/rwtest.sqlite3 ";
+    const string install_cmd = string(install_cmd_prefix) + db_file;
+    if (system(install_cmd.c_str()) != 0) {
+        isc_throw(isc::Unexpected,
+                  "Error setting up; command failed: " << install_cmd);
+    }
+
+    DataSourceClientContainer container("sqlite3",
+                                        Element::fromJSON(
+                                            "{\"database_file\": \"" +
+                                            string(db_file) + "\"}"));
+    ZoneUpdaterPtr updater = container.getInstance().getUpdater(zname, true);
+    masterLoad(rr_stream, zname, zclass, boost::bind(addRRset, updater, _1));
+    updater->commit();
+}
+
+} // end of unittest
+} // end of auth
+} // end of isc

+ 61 - 0
src/bin/auth/tests/datasrc_util.h

@@ -0,0 +1,61 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __AUTH_DATA_SOURCE_UTIL_H
+#define __AUTH_DATA_SOURCE_UTIL_H 1
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+
+#include <istream>
+
+namespace isc {
+namespace auth {
+namespace unittest {
+
+// Here we define utility modules for the convenience of tests that create
+// a data source client according to the specified conditions.
+
+/// \brief Create an SQLite3 data source client from a stream.
+///
+/// This function creates an SQLite3 DB file for the specified zone
+/// with specified content.  The zone will be created in the given
+/// SQLite3 database file.  The database file does not have to exist;
+/// this function will automatically create a new file for the test
+/// based on a template that only contains the necessary schema. If
+/// the given file already exists this function overrides the content
+/// (so basically the file must be an ephemeral one only for that test
+/// case).
+///
+/// The input stream must produce strings as the corresponding
+/// \c dns::masterLoad() function expects.
+///
+/// \param zclass The RR class of the zone
+/// \param zname The origin name of the zone
+/// \param db_file The SQLite3 data base file in which the zone data should be
+/// installed.
+/// \param rr_stream An input stream that produces zone data.
+void
+createSQLite3DB(dns::RRClass zclass, const dns::Name& zname,
+                const char* const db_file, std::istream& rr_stream);
+
+} // end of unittest
+} // end of auth
+} // end of isc
+
+#endif  // __AUTH_DATA_SOURCE_UTIL_H
+
+// Local Variables:
+// mode: c++
+// End:

+ 1 - 1
src/lib/datasrc/factory.h

@@ -163,7 +163,7 @@ public:
     ///
     /// \return Reference to the DataSourceClient instance contained in this
     ///         container.
-    DataSourceClient& getInstance() { return *instance_; }
+    DataSourceClient& getInstance() { return (*instance_); }
 
 private:
     DataSourceClient* instance_;

+ 4 - 2
src/lib/datasrc/sqlite3_accessor_link.cc

@@ -82,13 +82,15 @@ createInstance(isc::data::ConstElementPtr config, std::string& error) {
         error = "Configuration error: " + errors->str();
         return (NULL);
     }
-    std::string dbfile = config->get(CONFIG_ITEM_DATABASE_FILE)->stringValue();
+    const std::string dbfile =
+        config->get(CONFIG_ITEM_DATABASE_FILE)->stringValue();
     try {
         boost::shared_ptr<DatabaseAccessor> sqlite3_accessor(
             new SQLite3Accessor(dbfile, "IN")); // XXX: avoid hardcode RR class
         return (new DatabaseClient(isc::dns::RRClass::IN(), sqlite3_accessor));
     } catch (const std::exception& exc) {
-        error = std::string("Error creating sqlite3 datasource: ") + exc.what();
+        error = std::string("Error creating sqlite3 datasource: ") +
+            exc.what();
         return (NULL);
     } catch (...) {
         error = std::string("Error creating sqlite3 datasource, "

+ 0 - 1
src/lib/datasrc/tests/Makefile.am

@@ -107,7 +107,6 @@ EXTRA_DIST += testdata/mkbrokendb.c
 EXTRA_DIST += testdata/root.zone
 EXTRA_DIST += testdata/rrset_toWire1
 EXTRA_DIST += testdata/rrset_toWire2
-EXTRA_DIST += testdata/rwtest.sqlite3
 EXTRA_DIST += testdata/sql1.example.com.signed
 EXTRA_DIST += testdata/sql2.example.com.signed
 EXTRA_DIST += testdata/test-root.sqlite3

+ 1 - 1
src/lib/datasrc/tests/database_unittest.cc

@@ -1099,7 +1099,7 @@ public:
         // probably move this to some specialized templated method specific
         // to SQLite3 (or for even a longer term we should add an API to
         // purge the diffs table).
-        const char* const install_cmd = INSTALL_PROG " " TEST_DATA_DIR
+        const char* const install_cmd = INSTALL_PROG " " TEST_DATA_COMMONDIR
             "/rwtest.sqlite3 " TEST_DATA_BUILDDIR
             "/rwtest.sqlite3.copied";
         if (system(install_cmd) != 0) {

+ 3 - 3
src/lib/datasrc/tests/test_client.cc

@@ -65,9 +65,9 @@ createSQLite3Client(RRClass zclass, const Name& zname,
                     const char* const db_file, istream& rr_stream)
 {
     // We always begin with an empty template SQLite3 DB file and install
-    // the zone data from the zone file to ensure that the data source contains
-    // the exact given data, and only that data.
-    const char* const install_cmd_prefix = INSTALL_PROG " " TEST_DATA_DIR
+    // the zone data from the zone file to ensure both cases have the
+    // same test data.
+    const char* const install_cmd_prefix = INSTALL_PROG " " TEST_DATA_COMMONDIR
         "/rwtest.sqlite3 ";
     const string install_cmd = string(install_cmd_prefix) + db_file;
     if (system(install_cmd.c_str()) != 0) {

+ 1 - 0
src/lib/testutils/testdata/Makefile.am

@@ -27,6 +27,7 @@ EXTRA_DIST += rfc5155-example.zone.signed
 
 EXTRA_DIST += example.com
 EXTRA_DIST += example.sqlite3
+EXTRA_DIST += rwtest.sqlite3	# SQLite3 DB file as a template data source
 
 EXTRA_DIST += test1.zone.in
 EXTRA_DIST += test1-new.zone.in

+ 0 - 0
src/lib/datasrc/tests/testdata/rwtest.sqlite3


BIN
src/lib/testutils/testdata/auth_test.sqlite3.copied


BIN
src/lib/testutils/testdata/rwtest.sqlite3


+ 24 - 0
tests/lettuce/configurations/inmemory_over_sqlite3/secondary.conf

@@ -0,0 +1,24 @@
+{
+    "version": 2,
+    "Logging": {
+        "loggers": [ {
+            "debuglevel": 99,
+            "severity": "DEBUG",
+            "name": "auth"
+        } ]
+    },
+    "Auth": {
+        "datasources": [ {
+            "type": "memory",
+            "zones": [ {
+                "origin": "example.org",
+                "file": "data/example.org.sqlite3",
+	        "filetype": "sqlite3"
+            } ]
+	} ],
+        "listen_on": [ {
+            "port": 47806,
+            "address": "127.0.0.1"
+        } ]
+    }
+}

+ 9 - 0
tests/lettuce/features/inmemory_over_sqlite3.feature

@@ -0,0 +1,9 @@
+Feature: In-memory zone using SQLite3 backend
+    This feature tests the authoritative server configured with an in-memory
+    data source that uses the SQLite3 data source as the backend, and tests
+    scenarios that update the zone via incoming zone transfers.
+
+    Scenario: Load and response
+        Given I have bind10 running with configuration inmemory_over_sqlite3/secondary.conf
+        A query for www.example.org should have rcode NOERROR
+        The SOA serial for example.org should be 1234