BIND 10 master, updated. 672f129700dae33b701bb02069cf276238d66be3 [master] Merge branch 'trac1891'
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Apr 19 08:06:31 UTC 2012
The branch, master has been updated
via 672f129700dae33b701bb02069cf276238d66be3 (commit)
via bcb62dd7e4d8a3bca40e3725aa457074ada36134 (commit)
via 400ff18a8c98cd0c1c393ef32e1d76bb4222dce6 (commit)
via e7c91fe725369cabe19bd227e06176a117955461 (commit)
via 14a13b8494a53f2a488859ed27726f32e57781b6 (commit)
via 47f1415387f974e7ccdf7d95d7a380827486bc22 (commit)
via 9a4619a0a1ffdde67a58af51f3826e5c6a8da20b (commit)
via fb7201b9ff0aaa126ff82595b7a4c2f69ea8f4c7 (commit)
via bea9aaf1441dd9da91cc1197d02ea52c0d0095f1 (commit)
via d7cf5f81d983e95e4f8bd85637a0ae9785d94a9d (commit)
via 91cb18e244588b8a99ddf9b12fb99986b0258fdb (commit)
via 7aac25a59bfb9dbdbdbc4c8334204d24f7e0b131 (commit)
via 358beb2e1e15bcbe09438719e756f8641ea929d5 (commit)
via d68d574b69ee627b11982276312dfa70160b072a (commit)
from f93cd951e3ead684e4efbc8d2eaa523141e0cf65 (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 672f129700dae33b701bb02069cf276238d66be3
Merge: f93cd95 bcb62dd
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu Apr 19 00:58:32 2012 -0700
[master] Merge branch 'trac1891'
-----------------------------------------------------------------------
Summary of changes:
src/lib/datasrc/sqlite3_accessor.cc | 182 ++++++++++++--------
src/lib/datasrc/tests/database_unittest.cc | 16 +-
src/lib/datasrc/tests/faked_nsec3.cc | 13 ++
src/lib/datasrc/tests/faked_nsec3.h | 24 ++--
src/lib/datasrc/tests/sqlite3_accessor_unittest.cc | 177 ++++++++++++++++++-
tests/lettuce/data/example.org.sqlite3 | Bin 15360 -> 15360 bytes
tests/lettuce/features/terrain/transfer.py | 4 +-
tests/lettuce/features/xfrin_bind10.feature | 8 +
8 files changed, 325 insertions(+), 99 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/lib/datasrc/sqlite3_accessor.cc b/src/lib/datasrc/sqlite3_accessor.cc
index cbc3011..f3947f5 100644
--- a/src/lib/datasrc/sqlite3_accessor.cc
+++ b/src/lib/datasrc/sqlite3_accessor.cc
@@ -66,14 +66,16 @@ enum StatementID {
ITERATE = 9,
FIND_PREVIOUS = 10,
ADD_RECORD_DIFF = 11,
- GET_RECORD_DIFF = 12, // This is temporary for testing "add diff"
- LOW_DIFF_ID = 13,
- HIGH_DIFF_ID = 14,
- DIFF_RECS = 15,
- NSEC3 = 16,
- NSEC3_PREVIOUS = 17,
- NSEC3_LAST = 18,
- NUM_STATEMENTS = 19
+ LOW_DIFF_ID = 12,
+ HIGH_DIFF_ID = 13,
+ DIFF_RECS = 14,
+ NSEC3 = 15,
+ NSEC3_PREVIOUS = 16,
+ NSEC3_LAST = 17,
+ ADD_NSEC3_RECORD = 18,
+ DEL_ZONE_NSEC3_RECORDS = 19,
+ DEL_NSEC3_RECORD = 20,
+ NUM_STATEMENTS = 21
};
const char* const text_statements[NUM_STATEMENTS] = {
@@ -117,8 +119,6 @@ const char* const text_statements[NUM_STATEMENTS] = {
"INSERT INTO diffs " // ADD_RECORD_DIFF
"(zone_id, version, operation, name, rrtype, ttl, rdata) "
"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
- "SELECT name, rrtype, ttl, rdata, version, operation " // GET_RECORD_DIFF
- "FROM diffs WHERE zone_id = ?1 ORDER BY id, operation",
// Two statements to select the lowest ID and highest ID in a set of
// differences.
@@ -135,19 +135,27 @@ const char* const text_statements[NUM_STATEMENTS] = {
"WHERE zone_id=?1 AND id>=?2 and id<=?3 "
"ORDER BY id ASC",
- // Query to get the NSEC3 records
+ // NSEC3: Query to get the NSEC3 records
//
// The "1" in SELECT is for positioning the rdata column to the
// expected position, so we can reuse the same code as for other
// lookups.
"SELECT rdtype, ttl, 1, rdata FROM nsec3 WHERE zone_id=?1 AND "
"hash=?2",
- // For getting the previous NSEC3 hash
+ // NSEC3_PREVIOUS: For getting the previous NSEC3 hash
"SELECT DISTINCT hash FROM nsec3 WHERE zone_id=?1 AND hash < ?2 "
"ORDER BY hash DESC LIMIT 1",
- // And for wrap-around
+ // NSEC3_LAST: And for wrap-around
"SELECT DISTINCT hash FROM nsec3 WHERE zone_id=?1 "
"ORDER BY hash DESC LIMIT 1",
+ // ADD_NSEC3_RECORD: Add NSEC3-related (NSEC3 or NSEC3-covering RRSIG) RR
+ "INSERT INTO nsec3 (zone_id, hash, owner, ttl, rdtype, rdata) "
+ "VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
+ // DEL_ZONE_NSEC3_RECORDS: delete all NSEC3-related records from the zone
+ "DELETE FROM nsec3 WHERE zone_id=?1",
+ // DEL_NSEC3_RECORD: delete specified NSEC3-related records
+ "DELETE FROM nsec3 WHERE zone_id=?1 AND hash=?2 "
+ "AND rdtype=?3 AND rdata=?4"
};
struct SQLite3Parameters {
@@ -196,6 +204,7 @@ struct SQLite3Parameters {
bool in_transaction; // whether or not a transaction has been started
bool updating_zone; // whether or not updating the zone
int updated_zone_id; // valid only when in_transaction is true
+ string updated_zone_origin_; // ditto, and only needed to handle NSEC3s
private:
// statements_ are private and must be accessed via getStatement() outside
// of this structure.
@@ -210,6 +219,10 @@ private:
// statement, which is completed with a single "step" (normally within a
// single call to an SQLite3Database method). In particular, it cannot be
// used for "SELECT" variants, which generally expect multiple matching rows.
+//
+// The bindXXX methods are straightforward wrappers for the corresponding
+// sqlite3_bind_xxx functions that make bindings with the given parameters
+// on the statement maintained in this class.
class StatementProcessor {
public:
// desc will be used on failure in the what() message of the resulting
@@ -226,6 +239,33 @@ public:
sqlite3_reset(stmt_);
}
+ void bindInt(int index, int val) {
+ if (sqlite3_bind_int(stmt_, index, val) != SQLITE_OK) {
+ isc_throw(DataSourceError,
+ "failed to bind SQLite3 parameter: " <<
+ sqlite3_errmsg(dbparameters_.db_));
+ }
+ }
+
+ void bindInt64(int index, sqlite3_int64 val) {
+ if (sqlite3_bind_int64(stmt_, index, val) != SQLITE_OK) {
+ isc_throw(DataSourceError,
+ "failed to bind SQLite3 parameter: " <<
+ sqlite3_errmsg(dbparameters_.db_));
+ }
+ }
+
+ // For simplicity, we assume val is a NULL-terminated string, and the
+ // entire non NUL characters are to be bound. The destructor parameter
+ // is normally either SQLITE_TRANSIENT or SQLITE_STATIC.
+ void bindText(int index, const char* val, void(*destructor)(void*)) {
+ if (sqlite3_bind_text(stmt_, index, val, -1, destructor)
+ != SQLITE_OK) {
+ isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
+ sqlite3_errmsg(dbparameters_.db_));
+ }
+ }
+
void exec() {
if (sqlite3_step(stmt_) != SQLITE_DONE) {
sqlite3_reset(stmt_);
@@ -1021,19 +1061,22 @@ SQLite3Accessor::startUpdateZone(const string& zone_name, const bool replace) {
"start an SQLite3 update transaction").exec();
if (replace) {
+ // First, clear all current data from tables.
+ typedef pair<StatementID, const char* const> StatementSpec;
+ const StatementSpec delzone_stmts[] =
+ { StatementSpec(DEL_ZONE_RECORDS, "delete zone records"),
+ StatementSpec(DEL_ZONE_NSEC3_RECORDS,
+ "delete zone NSEC3 records") };
try {
- StatementProcessor delzone_exec(*dbparameters_, DEL_ZONE_RECORDS,
- "delete zone records");
-
- sqlite3_stmt* stmt = dbparameters_->getStatement(DEL_ZONE_RECORDS);
- sqlite3_clear_bindings(stmt);
- if (sqlite3_bind_int(stmt, 1, zone_info.second) != SQLITE_OK) {
- isc_throw(DataSourceError,
- "failed to bind SQLite3 parameter: " <<
- sqlite3_errmsg(dbparameters_->db_));
+ for (size_t i = 0;
+ i < sizeof(delzone_stmts) / sizeof(delzone_stmts[0]);
+ ++i) {
+ StatementProcessor delzone_proc(*dbparameters_,
+ delzone_stmts[i].first,
+ delzone_stmts[i].second);
+ delzone_proc.bindInt(1, zone_info.second);
+ delzone_proc.exec();
}
-
- delzone_exec.exec();
} catch (const DataSourceError&) {
// Once we start a transaction, if something unexpected happens
// we need to rollback the transaction so that a subsequent update
@@ -1047,6 +1090,7 @@ SQLite3Accessor::startUpdateZone(const string& zone_name, const bool replace) {
dbparameters_->in_transaction = true;
dbparameters_->updating_zone = true;
dbparameters_->updated_zone_id = zone_info.second;
+ dbparameters_->updated_zone_origin_ = zone_name;
return (zone_info);
}
@@ -1073,7 +1117,9 @@ SQLite3Accessor::commit() {
StatementProcessor(*dbparameters_, COMMIT,
"commit an SQLite3 transaction").exec();
dbparameters_->in_transaction = false;
+ dbparameters_->updating_zone = false;
dbparameters_->updated_zone_id = -1;
+ dbparameters_->updated_zone_origin_.clear();
}
void
@@ -1086,7 +1132,9 @@ SQLite3Accessor::rollback() {
StatementProcessor(*dbparameters_, ROLLBACK,
"rollback an SQLite3 transaction").exec();
dbparameters_->in_transaction = false;
+ dbparameters_->updating_zone = false;
dbparameters_->updated_zone_id = -1;
+ dbparameters_->updated_zone_origin_.clear();
}
namespace {
@@ -1096,29 +1144,19 @@ void
doUpdate(SQLite3Parameters& dbparams, StatementID stmt_id,
COLUMNS_TYPE update_params, const char* exec_desc)
{
- sqlite3_stmt* const stmt = dbparams.getStatement(stmt_id);
- StatementProcessor executer(dbparams, stmt_id, exec_desc);
+ StatementProcessor proc(dbparams, stmt_id, exec_desc);
int param_id = 0;
- if (sqlite3_bind_int(stmt, ++param_id, dbparams.updated_zone_id)
- != SQLITE_OK) {
- isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
- sqlite3_errmsg(dbparams.db_));
- }
+ proc.bindInt(++param_id, dbparams.updated_zone_id);
const size_t column_count =
sizeof(update_params) / sizeof(update_params[0]);
for (int i = 0; i < column_count; ++i) {
// The old sqlite3 data source API assumes NULL for an empty column.
// We need to provide compatibility at least for now.
- if (sqlite3_bind_text(stmt, ++param_id,
- update_params[i].empty() ? NULL :
- update_params[i].c_str(),
- -1, SQLITE_TRANSIENT) != SQLITE_OK) {
- isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
- sqlite3_errmsg(dbparams.db_));
- }
+ proc.bindText(++param_id, update_params[i].empty() ? NULL :
+ update_params[i].c_str(), SQLITE_TRANSIENT);
}
- executer.exec();
+ proc.exec();
}
}
@@ -1128,15 +1166,32 @@ SQLite3Accessor::addRecordToZone(const string (&columns)[ADD_COLUMN_COUNT]) {
isc_throw(DataSourceError, "adding record to SQLite3 "
"data source without transaction");
}
- doUpdate<const string (&)[DatabaseAccessor::ADD_COLUMN_COUNT]>(
+ doUpdate<const string (&)[ADD_COLUMN_COUNT]>(
*dbparameters_, ADD_RECORD, columns, "add record to zone");
}
void
SQLite3Accessor::addNSEC3RecordToZone(
- const string (&/*columns*/)[ADD_NSEC3_COLUMN_COUNT])
+ const string (&columns)[ADD_NSEC3_COLUMN_COUNT])
{
- isc_throw(NotImplemented, "not yet implemented");
+ if (!dbparameters_->updating_zone) {
+ isc_throw(DataSourceError, "adding NSEC3-related record to SQLite3 "
+ "data source without transaction");
+ }
+
+ // XXX: the current implementation of SQLite3 schema requires the 'owner'
+ // column, and the current implementation of getAllRecords() relies on it,
+ // while the addNSEC3RecordToZone interface doesn't provide it explicitly.
+ // We should revisit it at the design level, but for now we internally
+ // convert the given parameter to satisfy the internal requirements.
+ const string sqlite3_columns[ADD_NSEC3_COLUMN_COUNT + 1] =
+ { columns[ADD_NSEC3_HASH],
+ columns[ADD_NSEC3_HASH] + "." + dbparameters_->updated_zone_origin_,
+ columns[ADD_NSEC3_TTL],
+ columns[ADD_NSEC3_TYPE], columns[ADD_NSEC3_RDATA] };
+ doUpdate<const string (&)[ADD_NSEC3_COLUMN_COUNT + 1]>(
+ *dbparameters_, ADD_NSEC3_RECORD, sqlite3_columns,
+ "add NSEC3 record to zone");
}
void
@@ -1145,15 +1200,21 @@ SQLite3Accessor::deleteRecordInZone(const string (¶ms)[DEL_PARAM_COUNT]) {
isc_throw(DataSourceError, "deleting record in SQLite3 "
"data source without transaction");
}
- doUpdate<const string (&)[DatabaseAccessor::DEL_PARAM_COUNT]>(
+ doUpdate<const string (&)[DEL_PARAM_COUNT]>(
*dbparameters_, DEL_RECORD, params, "delete record from zone");
}
void
SQLite3Accessor::deleteNSEC3RecordInZone(
- const string (&/*params*/)[DEL_PARAM_COUNT])
+ const string (¶ms)[DEL_PARAM_COUNT])
{
- isc_throw(NotImplemented, "not yet implemented");
+ if (!dbparameters_->updating_zone) {
+ isc_throw(DataSourceError, "deleting NSEC3-related record in SQLite3 "
+ "data source without transaction");
+ }
+ doUpdate<const string (&)[DEL_PARAM_COUNT]>(
+ *dbparameters_, DEL_NSEC3_RECORD, params,
+ "delete NSEC3 record from zone");
}
void
@@ -1171,33 +1232,16 @@ SQLite3Accessor::addRecordDiff(int zone_id, uint32_t serial,
<< dbparameters_->updated_zone_id);
}
- sqlite3_stmt* const stmt = dbparameters_->getStatement(ADD_RECORD_DIFF);
- StatementProcessor executer(*dbparameters_, ADD_RECORD_DIFF,
- "add record diff");
+ StatementProcessor proc(*dbparameters_, ADD_RECORD_DIFF,
+ "add record diff");
int param_id = 0;
- if (sqlite3_bind_int(stmt, ++param_id, zone_id)
- != SQLITE_OK) {
- isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
- sqlite3_errmsg(dbparameters_->db_));
- }
- if (sqlite3_bind_int64(stmt, ++param_id, serial)
- != SQLITE_OK) {
- isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
- sqlite3_errmsg(dbparameters_->db_));
- }
- if (sqlite3_bind_int(stmt, ++param_id, operation)
- != SQLITE_OK) {
- isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
- sqlite3_errmsg(dbparameters_->db_));
- }
+ proc.bindInt(++param_id, zone_id);
+ proc.bindInt64(++param_id, serial);
+ proc.bindInt(++param_id, operation);
for (int i = 0; i < DIFF_PARAM_COUNT; ++i) {
- if (sqlite3_bind_text(stmt, ++param_id, params[i].c_str(),
- -1, SQLITE_TRANSIENT) != SQLITE_OK) {
- isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
- sqlite3_errmsg(dbparameters_->db_));
- }
+ proc.bindText(++param_id, params[i].c_str(), SQLITE_TRANSIENT);
}
- executer.exec();
+ proc.exec();
}
std::string
diff --git a/src/lib/datasrc/tests/database_unittest.cc b/src/lib/datasrc/tests/database_unittest.cc
index 5b3a5dc..602ed24 100644
--- a/src/lib/datasrc/tests/database_unittest.cc
+++ b/src/lib/datasrc/tests/database_unittest.cc
@@ -3002,10 +3002,9 @@ TYPED_TEST(DatabaseClientTest, addRRsetToNewZone) {
this->checkLastAdded(rrset_added);
}
-// Below we define a set of NSEC3 update tests. Right now this only works
-// for the mock DB, but the plan is to make it a TYPED_TEST to share the case
-// with SQLite3 implementation, too.
-
+//
+// Below we define a set of NSEC3 update tests.
+//
// Commonly used data for NSEC3 update tests below.
const char* const nsec3_hash = "1BB7SO0452U1QHL98UISNDD9218GELR5";
const char* const nsec3_rdata = "1 1 12 AABBCCDD "
@@ -3045,7 +3044,7 @@ nsec3Check(const vector<ConstRRsetPtr>& expected_rrsets,
actual_rrsets.begin(), actual_rrsets.end());
}
-TEST_F(MockDatabaseClientTest, addDeleteNSEC3InZone) {
+TYPED_TEST(DatabaseClientTest, addDeleteNSEC3InZone) {
// Add one NSEC3 RR to the zone, delete it, and add another one.
this->updater_ = this->client_->getUpdater(this->zname_, true);
const ConstRRsetPtr nsec3_rrset =
@@ -3066,7 +3065,7 @@ TEST_F(MockDatabaseClientTest, addDeleteNSEC3InZone) {
*this->current_accessor_);
}
-TEST_F(MockDatabaseClientTest, addDeleteNSEC3AndRRSIGToZone) {
+TYPED_TEST(DatabaseClientTest, addDeleteNSEC3AndRRSIGToZone) {
// Add one NSEC3 RR and its RRSIG to the zone, delete the RRSIG and add
// a new one.
this->updater_ = this->client_->getUpdater(this->zname_, true);
@@ -3639,10 +3638,7 @@ TYPED_TEST(DatabaseClientTest, journal) {
this->checkJournal(expected);
}
-// At the moment this only works for the mock accessor. Once sqlite3
-// accessor supports updating NSEC3, this should be merged to the previous
-// test
-TEST_F(MockDatabaseClientTest, journalForNSEC3) {
+TYPED_TEST(DatabaseClientTest, journalForNSEC3) {
// Similar to the previous test, but adding/deleting NSEC3 RRs, just to
// confirm that NSEC3 is not special for managing diffs.
const ConstRRsetPtr nsec3_rrset =
diff --git a/src/lib/datasrc/tests/faked_nsec3.cc b/src/lib/datasrc/tests/faked_nsec3.cc
index 4ca22a5..0a1823b 100644
--- a/src/lib/datasrc/tests/faked_nsec3.cc
+++ b/src/lib/datasrc/tests/faked_nsec3.cc
@@ -28,6 +28,19 @@ namespace isc {
namespace datasrc {
namespace test {
+// Constant data definitions
+
+const char* const nsec3_common = " 300 IN NSEC3 1 1 12 aabbccdd "
+ "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG";
+const char* const nsec3_rrsig_common = " 300 IN RRSIG NSEC3 5 3 3600 "
+ "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
+const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
+const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
+const char* const ns1_hash = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
+const char* const w_hash = "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
+const char* const xyw_hash = "2vptu5timamqttgl4luu9kg21e0aor3s";
+const char* const zzz_hash = "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN";
+
class TestNSEC3HashCreator::TestNSEC3Hash : public NSEC3Hash {
private:
typedef map<Name, string> NSEC3HashMap;
diff --git a/src/lib/datasrc/tests/faked_nsec3.h b/src/lib/datasrc/tests/faked_nsec3.h
index 51b4059..10d9444 100644
--- a/src/lib/datasrc/tests/faked_nsec3.h
+++ b/src/lib/datasrc/tests/faked_nsec3.h
@@ -31,26 +31,24 @@ namespace test {
//
// Commonly used NSEC3 suffix. It's incorrect to use it for all NSEC3s, but
// doesn't matter for the purpose of our tests.
-const char* const nsec3_common = " 300 IN NSEC3 1 1 12 aabbccdd "
- "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG";
+extern const char* const nsec3_common;
// Likewise, common RRSIG suffix for NSEC3s.
-const char* const nsec3_rrsig_common = " 300 IN RRSIG NSEC3 5 3 3600 "
- "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
+extern const char* const nsec3_rrsig_common;
// Some faked NSEC3 hash values commonly used in tests and the faked NSEC3Hash
// object.
//
// For apex (example.org)
-const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
+extern const char* const apex_hash;
+extern const char* const apex_hash_lower;
// For ns1.example.org
-const char* const ns1_hash = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
+extern const char* const ns1_hash;
// For w.example.org
-const char* const w_hash = "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
+extern const char* const w_hash;
// For x.y.w.example.org (lower-cased)
-const char* const xyw_hash = "2vptu5timamqttgl4luu9kg21e0aor3s";
+extern const char* const xyw_hash;
// For zzz.example.org.
-const char* const zzz_hash = "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN";
+extern const char* const zzz_hash;
// A simple faked NSEC3 hash calculator with a dedicated creator for it.
//
@@ -83,4 +81,8 @@ performNSEC3Test(ZoneFinder &finder);
}
}
-#endif
+#endif // FAKED_NSEC3_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc b/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc
index f3aea4e..bde3e0f 100644
--- a/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc
+++ b/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc
@@ -12,8 +12,7 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <algorithm>
-#include <vector>
+#include "faked_nsec3.h"
#include <datasrc/sqlite3_accessor.h>
@@ -21,14 +20,20 @@
#include <dns/rrclass.h>
+#include <sqlite3.h>
+
#include <gtest/gtest.h>
+
#include <boost/lexical_cast.hpp>
#include <boost/scoped_ptr.hpp>
+
+#include <algorithm>
+#include <vector>
#include <fstream>
-#include <sqlite3.h>
using namespace std;
using namespace isc::datasrc;
+using namespace isc::datasrc::test;
using boost::lexical_cast;
using isc::data::ConstElementPtr;
using isc::data::Element;
@@ -463,11 +468,11 @@ TEST(SQLite3Open, getDBNameExampleROOT) {
// Simple function to match records
void
checkRecordRow(const std::string columns[],
- const std::string& field0,
- const std::string& field1,
- const std::string& field2,
- const std::string& field3,
- const std::string& field4)
+ const std::string& field0, // for type
+ const std::string& field1, // for TTL
+ const std::string& field2, // for "sigtype"
+ const std::string& field3, // for rdata
+ const std::string& field4) // for name
{
EXPECT_EQ(field0, columns[DatabaseAccessor::TYPE_COLUMN]);
EXPECT_EQ(field1, columns[DatabaseAccessor::TTL_COLUMN]);
@@ -736,6 +741,23 @@ const char* const deleted_data[] = {
// Existing data to be removed commonly used by some of the tests below
"foo.bar.example.com.", "A", "192.0.2.1"
};
+const char* const nsec3_data[DatabaseAccessor::ADD_NSEC3_COLUMN_COUNT] = {
+ // example NSEC3 parameters. Using "apex_hash" just as a convenient
+ // shortcut; otherwise it has nothing to do with the zone apex for the
+ // purpose of this test.
+ apex_hash, "3600", "NSEC3",
+ "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR NS SOA"
+};
+const char* const nsec3_sig_data[DatabaseAccessor::ADD_NSEC3_COLUMN_COUNT] = {
+ ns1_hash, "3600", "RRSIG",
+ "NSEC3 5 3 3600 20000101000000 20000201000000 12345 "
+ "example.com. FAKEFAKEFAKE"
+};
+const char* const nsec3_deleted_data[] = {
+ // Delete parameters for nsec3_data
+ apex_hash, nsec3_data[DatabaseAccessor::ADD_NSEC3_TYPE],
+ nsec3_data[DatabaseAccessor::ADD_NSEC3_RDATA]
+};
class SQLite3Update : public SQLite3AccessorTest {
protected:
@@ -762,6 +784,7 @@ protected:
int zone_id;
std::string get_columns[DatabaseAccessor::COLUMN_COUNT];
std::string add_columns[DatabaseAccessor::ADD_COLUMN_COUNT];
+ std::string add_nsec3_columns[DatabaseAccessor::ADD_NSEC3_COLUMN_COUNT];
std::string del_params[DatabaseAccessor::DEL_PARAM_COUNT];
std::string diff_params[DatabaseAccessor::DIFF_PARAM_COUNT];
@@ -789,6 +812,28 @@ checkRecords(SQLite3Accessor& accessor, int zone_id, const std::string& name,
EXPECT_TRUE(it == expected_rows.end());
}
+// Similar to the previous one, but checking transactions on the nsec3 table.
+void
+checkNSEC3Records(SQLite3Accessor& accessor, int zone_id,
+ const std::string& hash,
+ vector<const char* const*> expected_rows)
+{
+ DatabaseAccessor::IteratorContextPtr iterator =
+ accessor.getNSEC3Records(hash, zone_id);
+ std::string columns[DatabaseAccessor::COLUMN_COUNT];
+ vector<const char* const*>::const_iterator it = expected_rows.begin();
+ while (iterator->getNext(columns)) {
+ ASSERT_TRUE(it != expected_rows.end());
+ checkRecordRow(columns, (*it)[DatabaseAccessor::ADD_NSEC3_TYPE],
+ (*it)[DatabaseAccessor::ADD_NSEC3_TTL],
+ "", // sigtype, should always be empty
+ (*it)[DatabaseAccessor::ADD_NSEC3_RDATA],
+ ""); // name, always empty
+ ++it;
+ }
+ EXPECT_TRUE(it == expected_rows.end());
+}
+
TEST_F(SQLite3Update, emptyUpdate) {
// If we do nothing between start and commit, the zone content
// should be intact.
@@ -811,6 +856,26 @@ TEST_F(SQLite3Update, flushZone) {
checkRecords(*accessor, zone_id, "foo.bar.example.com.", empty_stored);
}
+TEST_F(SQLite3Update, flushZoneWithNSEC3) {
+ // Similar to the previous case, but make sure the separate nsec3 table
+ // is also cleared. We first need to add something to the table.
+ zone_id = accessor->startUpdateZone("example.com.", false).second;
+ copy(nsec3_data, nsec3_data + DatabaseAccessor::ADD_NSEC3_COLUMN_COUNT,
+ add_nsec3_columns);
+ accessor->addNSEC3RecordToZone(add_nsec3_columns);
+ accessor->commit();
+
+ // Confirm it surely exists.
+ expected_stored.clear();
+ expected_stored.push_back(nsec3_data);
+ checkNSEC3Records(*accessor, zone_id, apex_hash, expected_stored);
+
+ // Then starting zone replacement. the NSEC3 record should have been
+ // removed.
+ zone_id = accessor->startUpdateZone("example.com.", true).second;
+ checkNSEC3Records(*accessor, zone_id, apex_hash, empty_stored);
+}
+
TEST_F(SQLite3Update, readWhileUpdate) {
zone_id = accessor->startUpdateZone("example.com.", true).second;
checkRecords(*accessor, zone_id, "foo.bar.example.com.", empty_stored);
@@ -924,6 +989,62 @@ TEST_F(SQLite3Update, addRecord) {
checkRecords(*accessor, zone_id, "newdata.example.com.", expected_stored);
}
+TEST_F(SQLite3Update, addNSEC3Record) {
+ // Similar to the previous test, but for NSEC3-related records
+ checkRecords(*accessor, zone_id, apex_hash, empty_stored);
+ checkRecords(*accessor, zone_id, ns1_hash, empty_stored);
+
+ zone_id = accessor->startUpdateZone("example.com.", false).second;
+ // Add an NSEC3
+ copy(nsec3_data, nsec3_data + DatabaseAccessor::ADD_NSEC3_COLUMN_COUNT,
+ add_nsec3_columns);
+ accessor->addNSEC3RecordToZone(add_nsec3_columns);
+
+ // Add an RRSIG for NSEC3
+ copy(nsec3_sig_data,
+ nsec3_sig_data + DatabaseAccessor::ADD_NSEC3_COLUMN_COUNT,
+ add_nsec3_columns);
+ accessor->addNSEC3RecordToZone(add_nsec3_columns);
+
+ // Check the stored data, before and after commit().
+ for (size_t i = 0; i < 2; ++i) {
+ expected_stored.clear();
+ expected_stored.push_back(nsec3_data);
+ checkNSEC3Records(*accessor, zone_id, apex_hash, expected_stored);
+
+ expected_stored.clear();
+ expected_stored.push_back(nsec3_sig_data);
+ checkNSEC3Records(*accessor, zone_id, ns1_hash, expected_stored);
+
+ if (i == 0) { // make sure commit() happens only once
+ accessor->commit();
+ }
+ }
+}
+
+TEST_F(SQLite3Update, nsec3IteratorOnAdd) {
+ // This test checks if an added NSEC3 record will appear in the iterator
+ // result, meeting the expectation of addNSEC3RecordToZone.
+ // Specifically, it checks if the name column is filled with the complete
+ // owner name.
+
+ // We'll replace the zone, and add one NSEC3 record, and only that one.
+ zone_id = accessor->startUpdateZone("example.com.", true).second;
+ copy(nsec3_data, nsec3_data + DatabaseAccessor::ADD_NSEC3_COLUMN_COUNT,
+ add_nsec3_columns);
+ accessor->addNSEC3RecordToZone(add_nsec3_columns);
+ accessor->commit();
+
+ // the zone should contain only one record we just added.
+ DatabaseAccessor::IteratorContextPtr context =
+ accessor->getAllRecords(zone_id);
+ string data[DatabaseAccessor::COLUMN_COUNT];
+ EXPECT_TRUE(context->getNext(data));
+ EXPECT_EQ(string(apex_hash) + ".example.com.",
+ data[DatabaseAccessor::NAME_COLUMN]);
+ EXPECT_FALSE(context->getNext(data));
+}
+
TEST_F(SQLite3Update, addThenRollback) {
zone_id = accessor->startUpdateZone("example.com.", false).second;
copy(new_data, new_data + DatabaseAccessor::ADD_COLUMN_COUNT,
@@ -934,7 +1055,11 @@ TEST_F(SQLite3Update, addThenRollback) {
expected_stored.push_back(new_data);
checkRecords(*accessor, zone_id, "newdata.example.com.", expected_stored);
+ // Rollback the transaction, and confirm the zone reverts to the previous
+ // state. We also start another update to check if the accessor can be
+ // reused for a new update after rollback.
accessor->rollback();
+ zone_id = accessor->startUpdateZone("example.com.", false).second;
checkRecords(*accessor, zone_id, "newdata.example.com.", empty_stored);
}
@@ -960,6 +1085,12 @@ TEST_F(SQLite3Update, duplicateAdd) {
TEST_F(SQLite3Update, invalidAdd) {
// An attempt of add before an explicit start of transaction
EXPECT_THROW(accessor->addRecordToZone(add_columns), DataSourceError);
+
+ // Same for addNSEC3.
+ copy(nsec3_data, nsec3_data + DatabaseAccessor::ADD_NSEC3_COLUMN_COUNT,
+ add_nsec3_columns);
+ EXPECT_THROW(accessor->addNSEC3RecordToZone(add_nsec3_columns),
+ DataSourceError);
}
TEST_F(SQLite3Update, deleteRecord) {
@@ -977,6 +1108,32 @@ TEST_F(SQLite3Update, deleteRecord) {
checkRecords(*accessor, zone_id, "foo.bar.example.com.", empty_stored);
}
+TEST_F(SQLite3Update, deleteNSEC3Record) {
+ // Similar to the previous test, but for NSEC3.
+ zone_id = accessor->startUpdateZone("example.com.", false).second;
+ checkNSEC3Records(*accessor, zone_id, apex_hash, empty_stored);
+
+ // We first need to add some record.
+ copy(nsec3_data, nsec3_data + DatabaseAccessor::ADD_NSEC3_COLUMN_COUNT,
+ add_nsec3_columns);
+ accessor->addNSEC3RecordToZone(add_nsec3_columns);
+
+ // Now it should exist.
+ expected_stored.clear();
+ expected_stored.push_back(nsec3_data);
+ checkNSEC3Records(*accessor, zone_id, apex_hash, expected_stored);
+
+ // Delete it, and confirm that.
+ copy(nsec3_deleted_data,
+ nsec3_deleted_data + DatabaseAccessor::DEL_PARAM_COUNT, del_params);
+ accessor->deleteNSEC3RecordInZone(del_params);
+ checkNSEC3Records(*accessor, zone_id, apex_hash, empty_stored);
+
+ // Commit the change, and confirm the deleted data still isn't there.
+ accessor->commit();
+ checkNSEC3Records(*accessor, zone_id, apex_hash, empty_stored);
+}
+
TEST_F(SQLite3Update, deleteThenRollback) {
zone_id = accessor->startUpdateZone("example.com.", false).second;
@@ -1023,6 +1180,10 @@ TEST_F(SQLite3Update, deleteNonexistent) {
TEST_F(SQLite3Update, invalidDelete) {
// An attempt of delete before an explicit start of transaction
EXPECT_THROW(accessor->deleteRecordInZone(del_params), DataSourceError);
+
+ // Same for NSEC3.
+ EXPECT_THROW(accessor->deleteNSEC3RecordInZone(del_params),
+ DataSourceError);
}
TEST_F(SQLite3Update, emptyTransaction) {
diff --git a/tests/lettuce/data/example.org.sqlite3 b/tests/lettuce/data/example.org.sqlite3
index 715a092..427fa24 100644
Binary files a/tests/lettuce/data/example.org.sqlite3 and b/tests/lettuce/data/example.org.sqlite3 differ
diff --git a/tests/lettuce/features/terrain/transfer.py b/tests/lettuce/features/terrain/transfer.py
index 305e677..4ba45b8 100644
--- a/tests/lettuce/features/terrain/transfer.py
+++ b/tests/lettuce/features/terrain/transfer.py
@@ -58,7 +58,7 @@ class TransferResult(object):
if len(line) > 0 and line[0] != ';':
self.records.append(line)
- at step('An AXFR transfer of ([\w.]+)(?: from ([^:]+)(?::([0-9]+))?)?')
+ at step('An AXFR transfer of ([\w.]+)(?: from ([^:]+|\[[0-9a-fA-F:]+\])(?::([0-9]+))?)?')
def perform_axfr(step, zone_name, address, port):
"""
Perform an AXFR transfer, and store the result as an instance of
@@ -72,6 +72,8 @@ def perform_axfr(step, zone_name, address, port):
"""
if address is None:
address = "127.0.0.1"
+ # convert [IPv6_addr] to IPv6_addr:
+ address = re.sub(r"\[(.+)\]", r"\1", address)
if port is None:
port = 47806
args = [ 'dig', 'AXFR', '@' + str(address), '-p', str(port), zone_name ]
diff --git a/tests/lettuce/features/xfrin_bind10.feature b/tests/lettuce/features/xfrin_bind10.feature
index 69043d8..2a56356 100644
--- a/tests/lettuce/features/xfrin_bind10.feature
+++ b/tests/lettuce/features/xfrin_bind10.feature
@@ -21,3 +21,11 @@ Feature: Xfrin
When I send bind10 the command Xfrin retransfer example.org IN ::1 47807
Then wait for new bind10 stderr message XFRIN_TRANSFER_SUCCESS not XFRIN_XFR_PROCESS_FAILURE
A query for www.example.org should have rcode NOERROR
+
+ # The transferred zone should have 11 non-NSEC3 RRs and 1 NSEC3 RR.
+ # The following check will get these by AXFR, so the total # of RRs
+ # should be 13, counting the duplicated SOA.
+ # At this point we can confirm both in and out of AXFR for a zone
+ # containing an NSEC3 RR.
+ When I do an AXFR transfer of example.org from ::1 47807
+ Then transfer result should have 13 rrs
More information about the bind10-changes
mailing list