BIND 10 master, updated. 019ca218027a218921519f205139b96025df2bb5 [master] Merge branch 'trac2500'

BIND 10 source code commits bind10-changes at lists.isc.org
Fri Jan 11 02:01:01 UTC 2013


The branch, master has been updated
       via  019ca218027a218921519f205139b96025df2bb5 (commit)
       via  a095d57b989aca503c22bfe2121df389abdbd392 (commit)
       via  a8e4e8678710187bbd044689a0ed603f5182fda8 (commit)
       via  042731613c48d83d96bd3a4911b397977ae783dc (commit)
       via  6926ec8a661213e78e73922d093c9883a5d16eb1 (commit)
       via  331f01d140ccc6d2f9a37fb483581bfdac1f5cfa (commit)
       via  79007cc52b34b9cca6259c86a479ddc5100f15f5 (commit)
       via  26a6ff11a1634de2624080eeb424df4d782496f4 (commit)
       via  6010b776a5a76c7c9df5025e86c7902992750615 (commit)
      from  6278daf2fc808fd4a311a97529815db1ef216e79 (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 019ca218027a218921519f205139b96025df2bb5
Merge: 6278daf a095d57
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Thu Jan 10 17:39:00 2013 -0800

    [master] Merge branch 'trac2500'

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

Summary of changes:
 src/bin/loadzone/tests/correct/include.db          |    4 +-
 src/bin/loadzone/tests/correct/mix1.db             |    4 +-
 src/bin/loadzone/tests/correct/mix2.db             |    4 +-
 src/bin/loadzone/tests/correct/ttl1.db             |    4 +-
 src/bin/loadzone/tests/correct/ttl2.db             |    4 +-
 src/bin/loadzone/tests/correct/ttlext.db           |    4 +-
 src/bin/xfrin/tests/xfrin_test.py                  |    4 +-
 src/bin/xfrout/tests/xfrout_test.py.in             |    2 +-
 .../tests/memory/rdata_serialization_unittest.cc   |   24 +--
 src/lib/dns/Makefile.am                            |    1 +
 src/lib/dns/gen-rdatacode.py.in                    |    4 +-
 src/lib/dns/rdata/generic/detail/lexer_util.h      |   70 +++++++++
 src/lib/dns/rdata/generic/soa_6.cc                 |  117 ++++++++++----
 src/lib/dns/tests/rdata_soa_unittest.cc            |  160 +++++++++++++++++++-
 src/lib/dns/tests/rdata_txt_like_unittest.cc       |    2 -
 src/lib/dns/tests/rdata_unittest.cc                |    3 +-
 src/lib/dns/tests/rdata_unittest.h                 |    1 +
 17 files changed, 340 insertions(+), 72 deletions(-)
 create mode 100644 src/lib/dns/rdata/generic/detail/lexer_util.h

-----------------------------------------------------------------------
diff --git a/src/bin/loadzone/tests/correct/include.db b/src/bin/loadzone/tests/correct/include.db
index a9eeca3..53871bb 100644
--- a/src/bin/loadzone/tests/correct/include.db
+++ b/src/bin/loadzone/tests/correct/include.db
@@ -1,8 +1,6 @@
 $ORIGIN include.   ; initialize origin
 $TTL 300
-; this needs #2500
-;@			IN SOA	ns hostmaster (
-@			IN SOA	ns.include. hostmaster.include. (
+@			IN SOA	ns hostmaster (
 				1        ; serial
 				3600
 				1800
diff --git a/src/bin/loadzone/tests/correct/mix1.db b/src/bin/loadzone/tests/correct/mix1.db
index 5bc0a95..059fde7 100644
--- a/src/bin/loadzone/tests/correct/mix1.db
+++ b/src/bin/loadzone/tests/correct/mix1.db
@@ -1,7 +1,5 @@
 $ORIGIN mix1.
-; this needs #2500
-;@			IN SOA	ns hostmaster (
-@			IN SOA	ns.mix1. hostmaster.mix1. (
+@			IN SOA	ns hostmaster (
 				1        ; serial
 				3600
 				1800
diff --git a/src/bin/loadzone/tests/correct/mix2.db b/src/bin/loadzone/tests/correct/mix2.db
index e43b943..e89c2af 100644
--- a/src/bin/loadzone/tests/correct/mix2.db
+++ b/src/bin/loadzone/tests/correct/mix2.db
@@ -1,7 +1,5 @@
 $ORIGIN mix2.
-; this needs #2500
-;@		1	IN SOA	ns hostmaster (
-@		1	IN SOA	ns.mix2. hostmaster.mix2. (
+@		1	IN SOA	ns hostmaster (
 				1        ; serial
 				3600
 				1800
diff --git a/src/bin/loadzone/tests/correct/ttl1.db b/src/bin/loadzone/tests/correct/ttl1.db
index fec0813..7f04ff8 100644
--- a/src/bin/loadzone/tests/correct/ttl1.db
+++ b/src/bin/loadzone/tests/correct/ttl1.db
@@ -1,7 +1,5 @@
 $ORIGIN ttl1.
-; this needs #2500
-;@			IN SOA	ns hostmaster (
-@			IN SOA	ns.ttl1. hostmaster.ttl1. (
+@			IN SOA	ns hostmaster (
 				1        ; serial
 				3600
 				1800
diff --git a/src/bin/loadzone/tests/correct/ttl2.db b/src/bin/loadzone/tests/correct/ttl2.db
index 4705978..b7df040 100644
--- a/src/bin/loadzone/tests/correct/ttl2.db
+++ b/src/bin/loadzone/tests/correct/ttl2.db
@@ -1,7 +1,5 @@
 $ORIGIN ttl2.
-; this needs #2500
-;@		1	IN SOA	ns hostmaster (
-@		1	IN SOA	ns.ttl2. hostmaster.ttl2 (
+@		1	IN SOA	ns hostmaster (
 				1        ; serial
 				3600
 				1800
diff --git a/src/bin/loadzone/tests/correct/ttlext.db b/src/bin/loadzone/tests/correct/ttlext.db
index f8c83b0..844f452 100644
--- a/src/bin/loadzone/tests/correct/ttlext.db
+++ b/src/bin/loadzone/tests/correct/ttlext.db
@@ -1,7 +1,5 @@
 $ORIGIN ttlext.
-; this needs #2500
-;@			IN SOA	ns hostmaster (
-@			IN SOA	ns.ttlext. hostmaster.ttlext. (
+@			IN SOA	ns hostmaster (
 				1        ; serial
 				3600
 				1800
diff --git a/src/bin/xfrin/tests/xfrin_test.py b/src/bin/xfrin/tests/xfrin_test.py
index b7fe056..99c5e1e 100644
--- a/src/bin/xfrin/tests/xfrin_test.py
+++ b/src/bin/xfrin/tests/xfrin_test.py
@@ -60,7 +60,7 @@ TSIG_KEY = TSIGKey("example.com:SFuWd/q99SzF8Yzd1QbB9g==")
 
 # SOA intended to be used for the new SOA as a result of transfer.
 soa_rdata = Rdata(RRType.SOA(), TEST_RRCLASS,
-                  'master.example.com. admin.example.com ' +
+                  'master.example.com. admin.example.com. ' +
                   '1234 3600 1800 2419200 7200')
 soa_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA(), RRTTL(3600))
 soa_rrset.add_rdata(soa_rdata)
@@ -68,7 +68,7 @@ soa_rrset.add_rdata(soa_rdata)
 # SOA intended to be used for the current SOA at the secondary side.
 # Note that its serial is smaller than that of soa_rdata.
 begin_soa_rdata = Rdata(RRType.SOA(), TEST_RRCLASS,
-                        'master.example.com. admin.example.com ' +
+                        'master.example.com. admin.example.com. ' +
                         '1230 3600 1800 2419200 7200')
 begin_soa_rrset = RRset(TEST_ZONE_NAME, TEST_RRCLASS, RRType.SOA(), RRTTL(3600))
 begin_soa_rrset.add_rdata(begin_soa_rdata)
diff --git a/src/bin/xfrout/tests/xfrout_test.py.in b/src/bin/xfrout/tests/xfrout_test.py.in
index 6e3f4a8..774187f 100644
--- a/src/bin/xfrout/tests/xfrout_test.py.in
+++ b/src/bin/xfrout/tests/xfrout_test.py.in
@@ -249,7 +249,7 @@ class TestXfroutSessionBase(unittest.TestCase):
             # In the RDATA only the serial matters.
             for i in range(0, num_soa):
                 soa.add_rdata(Rdata(RRType.SOA(), soa_class,
-                                    'm r ' + str(ixfr) + ' 1 1 1 1'))
+                                    'm. r. ' + str(ixfr) + ' 1 1 1 1'))
             msg.add_rrset(Message.SECTION_AUTHORITY, soa)
 
         renderer = MessageRenderer()
diff --git a/src/lib/datasrc/tests/memory/rdata_serialization_unittest.cc b/src/lib/datasrc/tests/memory/rdata_serialization_unittest.cc
index 4f82f7b..a45c2bd 100644
--- a/src/lib/datasrc/tests/memory/rdata_serialization_unittest.cc
+++ b/src/lib/datasrc/tests/memory/rdata_serialization_unittest.cc
@@ -71,20 +71,20 @@ struct TestRdata {
 // unusual and corner cases).
 const TestRdata test_rdata_list[] = {
     {"IN", "A", "192.0.2.1", 0},
-    {"IN", "NS", "ns.example.com", 0},
-    {"IN", "CNAME", "cname.example.com", 0},
-    {"IN", "SOA", "ns.example.com root.example.com 0 0 0 0 0", 0},
-    {"IN", "PTR", "reverse.example.com", 0},
+    {"IN", "NS", "ns.example.com.", 0},
+    {"IN", "CNAME", "cname.example.com.", 0},
+    {"IN", "SOA", "ns.example.com. root.example.com. 0 0 0 0 0", 0},
+    {"IN", "PTR", "reverse.example.com.", 0},
     {"IN", "HINFO", "\"cpu-info\" \"OS-info\"", 1},
-    {"IN", "MINFO", "root.example.com mbox.example.com", 0},
-    {"IN", "MX", "10 mx.example.com", 0},
+    {"IN", "MINFO", "root.example.com. mbox.example.com.", 0},
+    {"IN", "MX", "10 mx.example.com.", 0},
     {"IN", "TXT", "\"test1\" \"test 2\"", 1},
-    {"IN", "RP", "root.example.com. rp-text.example.com", 0},
-    {"IN", "AFSDB", "1 afsdb.example.com", 0},
+    {"IN", "RP", "root.example.com. rp-text.example.com.", 0},
+    {"IN", "AFSDB", "1 afsdb.example.com.", 0},
     {"IN", "AAAA", "2001:db8::1", 0},
-    {"IN", "SRV", "1 0 10 target.example.com", 0},
-    {"IN", "NAPTR", "100 50 \"s\" \"http\" \"\" _http._tcp.example.com", 1},
-    {"IN", "DNAME", "dname.example.com", 0},
+    {"IN", "SRV", "1 0 10 target.example.com.", 0},
+    {"IN", "NAPTR", "100 50 \"s\" \"http\" \"\" _http._tcp.example.com.", 1},
+    {"IN", "DNAME", "dname.example.com.", 0},
     {"IN", "DS", "12892 5 2 5F0EB5C777586DE18DA6B5", 1},
     {"IN", "SSHFP", "1 1 dd465c09cfa51fb45020cc83316fff", 1},
     // We handle RRSIG separately, so it's excluded from the list
@@ -98,7 +98,7 @@ const TestRdata test_rdata_list[] = {
     {"IN", "TYPE65000", "\\# 3 010203", 1}, // some "custom" type
     {"IN", "TYPE65535", "\\# 0", 1},        // max RR type, 0-length RDATA
     {"CH", "A", "\\# 2 0102", 1}, // A RR for non-IN class; varlen data
-    {"CH", "NS", "ns.example.com", 0}, // class CH, generic data
+    {"CH", "NS", "ns.example.com.", 0}, // class CH, generic data
     {"CH", "TXT", "BIND10", 1},        // ditto
     {"HS", "A", "\\# 5 0102030405", 1}, // A RR for non-IN class; varlen data
     {NULL, NULL, NULL, 0}
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 3f6ae63..7466b64 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -23,6 +23,7 @@ EXTRA_DIST += rdata/generic/cname_5.cc
 EXTRA_DIST += rdata/generic/cname_5.h
 EXTRA_DIST += rdata/generic/detail/char_string.cc
 EXTRA_DIST += rdata/generic/detail/char_string.h
+EXTRA_DIST += rdata/generic/detail/lexer_util.h
 EXTRA_DIST += rdata/generic/detail/nsec_bitmap.cc
 EXTRA_DIST += rdata/generic/detail/nsec_bitmap.h
 EXTRA_DIST += rdata/generic/detail/nsec3param_common.cc
diff --git a/src/lib/dns/gen-rdatacode.py.in b/src/lib/dns/gen-rdatacode.py.in
index 2bf9de6..88bff6c 100755
--- a/src/lib/dns/gen-rdatacode.py.in
+++ b/src/lib/dns/gen-rdatacode.py.in
@@ -32,8 +32,8 @@ import sys
 #
 # Example:
 #     new_rdata_factory_users = [('a', 'in'), ('a', 'ch'), ('soa', 'generic')]
-new_rdata_factory_users = [('aaaa', 'in'), ('txt', 'generic'),
-                           ('spf', 'generic')]
+new_rdata_factory_users = [('soa', 'generic'), ('txt', 'generic'),
+                           ('aaaa', 'in'), ('spf', 'generic')]
 
 re_typecode = re.compile('([\da-z]+)_(\d+)')
 classcode2txt = {}
diff --git a/src/lib/dns/rdata/generic/detail/lexer_util.h b/src/lib/dns/rdata/generic/detail/lexer_util.h
new file mode 100644
index 0000000..89df5a0
--- /dev/null
+++ b/src/lib/dns/rdata/generic/detail/lexer_util.h
@@ -0,0 +1,70 @@
+// Copyright (C) 2013  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 DNS_RDATA_LEXER_UTIL_H
+#define DNS_RDATA_LEXER_UTIL_H 1
+
+#include <dns/name.h>
+#include <dns/master_lexer.h>
+
+/// \file lexer_util.h
+/// \brief Utilities for extracting RDATA fields from lexer.
+///
+/// This file intends to define convenient small routines that can be
+/// commonly used in the RDATA implementation to build RDATA fields from
+/// a \c MasterLexer.
+
+namespace isc {
+namespace dns {
+namespace rdata {
+namespace generic {
+namespace detail {
+
+/// \brief Construct a Name object using a master lexer and optional origin.
+///
+/// This is a convenient shortcut of commonly used code pattern that would
+/// be used to build RDATA that contain a domain name field.
+///
+/// Note that this function throws an exception against invalid input.
+/// The (direct or indirect) caller's responsibility needs to expect and
+/// handle exceptions appropriately.
+///
+/// \throw MasterLexer::LexerError The next token from lexer is not string.
+/// \throw Other Exceptions from the \c Name class constructor if the next
+/// string token from the lexer does not represent a valid name.
+///
+/// \param lexer A \c MasterLexer object.  Its next token is expected to be
+/// a string that represent a domain name.
+/// \param origin If non NULL, specifies the origin of the name to be
+/// constructed.
+///
+/// \return A new Name object that corresponds to the next string token of
+/// the \c lexer.
+inline Name
+createNameFromLexer(MasterLexer& lexer, const Name* origin) {
+    const MasterToken::StringRegion& str_region =
+        lexer.getNextToken(MasterToken::STRING).getStringRegion();
+    return (Name(str_region.beg, str_region.len, origin));
+}
+
+} // namespace detail
+} // namespace generic
+} // namespace rdata
+} // namespace dns
+} // namespace isc
+#endif  // DNS_RDATA_LEXER_UTIL_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/rdata/generic/soa_6.cc b/src/lib/dns/rdata/generic/soa_6.cc
index 3ff2f08..56eb7a2 100644
--- a/src/lib/dns/rdata/generic/soa_6.cc
+++ b/src/lib/dns/rdata/generic/soa_6.cc
@@ -14,22 +14,29 @@
 
 #include <config.h>
 
-#include <string>
-
-#include <boost/static_assert.hpp>
-#include <boost/lexical_cast.hpp>
-
 #include <exceptions/exceptions.h>
 
 #include <util/buffer.h>
 #include <dns/name.h>
+#include <dns/master_lexer.h>
+#include <dns/master_loader.h>
+#include <dns/master_loader_callbacks.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 
+#include <dns/rdata/generic/detail/lexer_util.h>
+
+#include <boost/static_assert.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <string>
+#include <sstream>
+
 using namespace std;
 using boost::lexical_cast;
 using namespace isc::util;
+using isc::dns::rdata::generic::detail::createNameFromLexer;
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -42,35 +49,85 @@ SOA::SOA(InputBuffer& buffer, size_t) :
     buffer.readData(numdata_, sizeof(numdata_));
 }
 
+namespace {
+void
+fillParameters(MasterLexer& lexer, uint8_t numdata[20]) {
+    // Copy serial, refresh, retry, expire, minimum.  We accept the extended
+    // TTL-compatible style for the latter four.
+    OutputBuffer buffer(20);
+    buffer.writeUint32(lexer.getNextToken(MasterToken::NUMBER).getNumber());
+    for (int i = 0; i < 4; ++i) {
+        buffer.writeUint32(RRTTL(lexer.getNextToken(MasterToken::STRING).
+                                 getString()).getValue());
+    }
+    memcpy(numdata,  buffer.getData(), buffer.getLength());
+}
+}
+
+/// \brief Constructor from string.
+///
+/// The given string must represent a valid SOA RDATA.  There can be extra
+/// space characters at the beginning or end of the text (which are simply
+/// ignored), but other extra text, including a new line, will make the
+/// construction fail with an exception.
+///
+/// The MNAME and RNAME must be absolute since there's no parameter that
+/// specifies the origin name; if these are not absolute, \c MissingNameOrigin
+/// exception will be thrown.  These must not be represented as a quoted
+/// string.
+///
+/// See the construction that takes \c MasterLexer for other fields.
+///
+/// \throw Others Exception from the Name and RRTTL constructors.
+/// \throw InvalidRdataText Other general syntax errors.
 SOA::SOA(const std::string& soastr) :
-    mname_("."), rname_(".")    // quick hack workaround
+    // Fill in dummy name and replace them soon below.
+    mname_(Name::ROOT_NAME()), rname_(Name::ROOT_NAME())
 {
-    istringstream iss(soastr);
-    string token;
-
-    iss >> token;
-    if (iss.bad() || iss.fail()) {
-        isc_throw(InvalidRdataText, "Invalid SOA MNAME");
+    try {
+        std::istringstream ss(soastr);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+
+        mname_ = createNameFromLexer(lexer, NULL);
+        rname_ = createNameFromLexer(lexer, NULL);
+        fillParameters(lexer, numdata_);
+
+        if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+            isc_throw(InvalidRdataText, "extra input text for SOA: "
+                      << soastr);
+        }
+    } catch (const MasterLexer::LexerError& ex) {
+        isc_throw(InvalidRdataText, "Failed to construct SOA from '" <<
+                  soastr << "': " << ex.what());
     }
-    mname_ = Name(token);
-    iss >> token;
-    if (iss.bad() || iss.fail()) {
-        isc_throw(InvalidRdataText, "Invalid SOA RNAME");
-    }
-    rname_ = Name(token);
+}
 
-    uint32_t serial, refresh, retry, expire, minimum;
-    iss >> serial >> refresh >> retry >> expire >> minimum;
-    if (iss.rdstate() != ios::eofbit) {
-        isc_throw(InvalidRdataText, "Invalid SOA format");
-    }
-    OutputBuffer buffer(20);
-    buffer.writeUint32(serial);
-    buffer.writeUint32(refresh);
-    buffer.writeUint32(retry);
-    buffer.writeUint32(expire);
-    buffer.writeUint32(minimum);
-    memcpy(numdata_,  buffer.getData(), buffer.getLength());
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual representation
+/// of an SOA RDATA.  The MNAME and RNAME fields can be non absolute if
+/// \c origin is non NULL, in which case \c origin is used to make them
+/// absolute.  These must not be represented as a quoted string.
+///
+/// The REFRESH, RETRY, EXPIRE, and MINIMUM fields can be either a valid
+/// decimal representation of an unsigned 32-bit integer or other
+/// valid textual representation of \c RRTTL such as "1H" (which means 3600).
+///
+/// \throw MasterLexer::LexerError General parsing error such as missing field.
+/// \throw Other Exceptions from the Name and RRTTL constructors if
+/// construction of textual fields as these objects fail.
+///
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+/// \param origin If non NULL, specifies the origin of MNAME and RNAME when
+/// they are non absolute.
+SOA::SOA(MasterLexer& lexer, const Name* origin,
+         MasterLoader::Options, MasterLoaderCallbacks&) :
+    mname_(createNameFromLexer(lexer, origin)),
+    rname_(createNameFromLexer(lexer, origin))
+{
+    fillParameters(lexer, numdata_);
 }
 
 SOA::SOA(const Name& mname, const Name& rname, uint32_t serial,
diff --git a/src/lib/dns/tests/rdata_soa_unittest.cc b/src/lib/dns/tests/rdata_soa_unittest.cc
index 52f0601..ed1c29f 100644
--- a/src/lib/dns/tests/rdata_soa_unittest.cc
+++ b/src/lib/dns/tests/rdata_soa_unittest.cc
@@ -33,15 +33,129 @@ using namespace isc::dns::rdata;
 namespace {
 class Rdata_SOA_Test : public RdataTest {
 protected:
-    Rdata_SOA_Test() : rdata_soa(Name("ns.example.com"),
-                                 Name("root.example.com"),
-                                 2010012601, 3600, 300, 3600000, 1200)
+    Rdata_SOA_Test() :
+        rdata_soa(Name("ns.example.com"),
+                  Name("root.example.com"),
+                  2010012601, 3600, 300, 3600000, 1200)
     {}
+
+    // Common check to see if the given text can be used to construct SOA
+    // Rdata that is identical rdata_soa.
+    void checkFromText(const char* soa_txt, const Name* origin = NULL) {
+        std::stringstream ss(soa_txt);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+
+        if (origin == NULL) {
+            // from-string constructor works correctly only when origin
+            // is NULL (by its nature).
+            EXPECT_EQ(0, generic::SOA(soa_txt).compare(rdata_soa));
+        }
+        EXPECT_EQ(0, generic::SOA(lexer, origin, MasterLoader::DEFAULT,
+                                  loader_cb).compare(rdata_soa));
+    }
+
+    // Common check if given text (which is invalid as SOA RDATA) is rejected
+    // with the specified type of exception: ExForString is the expected
+    // exception for the "from string" constructor; ExForLexer is for the
+    // constructor with master lexer.
+    template <typename ExForString, typename ExForLexer>
+    void checkFromBadTexxt(const char* soa_txt, const Name* origin = NULL) {
+        EXPECT_THROW(generic::SOA soa(soa_txt), ExForString);
+
+        std::stringstream ss(soa_txt);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+        EXPECT_THROW(generic::SOA soa(lexer, origin, MasterLoader::DEFAULT,
+                                      loader_cb), ExForLexer);
+    }
+
     const generic::SOA rdata_soa;
 };
 
 TEST_F(Rdata_SOA_Test, createFromText) {
-    //TBD
+    // A simple case.
+    checkFromText("ns.example.com. root.example.com. "
+                  "2010012601 3600 300 3600000 1200");
+
+    // Beginning and trailing space are ignored.
+    checkFromText("  ns.example.com. root.example.com. "
+                  "2010012601 3600 300 3600000 1200  ");
+
+    // using extended TTL-like form for some parameters.
+    checkFromText("ns.example.com. root.example.com. "
+                  "2010012601 1H 5M 1000H 20M");
+
+    // multi-line.
+    checkFromText("ns.example.com. (root.example.com.\n"
+                  "2010012601 1H 5M 1000H) 20M");
+
+    // relative names for MNAME and RNAME with a separate origin (lexer
+    // version only)
+    const Name origin("example.com");
+    checkFromText("ns root 2010012601 1H 5M 1000H 20M", &origin);
+
+    // with the '@' notation with a separate origin (lexer version only)
+    const Name full_mname("ns.example.com");
+    checkFromText("@ root.example.com. 2010012601 1H 5M 1000H 20M",
+                  &full_mname);
+
+    // bad MNAME/RNAMEs
+    checkFromBadTexxt<EmptyLabel, EmptyLabel>(
+        "bad..example. . 2010012601 1H 5M 1000H 20M");
+    checkFromBadTexxt<EmptyLabel, EmptyLabel>(
+        ". bad..example. 2010012601 1H 5M 1000H 20M");
+
+    // Names shouldn't be quoted. (Note: on completion of #2534, the resulting
+    // exception will be different).
+    checkFromBadTexxt<MissingNameOrigin, MissingNameOrigin>(
+        "\".\" . 0 0 0 0 0");
+    checkFromBadTexxt<MissingNameOrigin, MissingNameOrigin>(
+        ". \".\" 0 0 0 0 0");
+
+    // Missing MAME or RNAME: for the string version, the serial would be
+    // tried as RNAME and result in "not absolute".  For the lexer version,
+    // it reaches the end-of-line, missing min TTL.
+    checkFromBadTexxt<MissingNameOrigin, MasterLexer::LexerError>(
+        ". 2010012601 0 0 0 0", &Name::ROOT_NAME());
+
+    // bad serial.  the string version converts lexer error to
+    // InvalidRdataText.
+    checkFromBadTexxt<InvalidRdataText, MasterLexer::LexerError>(
+        ". . bad 0 0 0 0");
+
+    // bad serial; exceeding the uint32_t range (4294967296 = 2^32)
+    checkFromBadTexxt<InvalidRdataText, MasterLexer::LexerError>(
+        ". . 4294967296 0 0 0 0");
+
+    // Bad format for other numeric parameters.  These will be tried as a TTL,
+    // and result in an exception there.
+    checkFromBadTexxt<InvalidRRTTL, InvalidRRTTL>(". . 2010012601 bad 0 0 0");
+    checkFromBadTexxt<InvalidRRTTL, InvalidRRTTL>(
+        ". . 2010012601 4294967296 0 0 0");
+    checkFromBadTexxt<InvalidRRTTL, InvalidRRTTL>(". . 2010012601 0 bad 0 0");
+    checkFromBadTexxt<InvalidRRTTL, InvalidRRTTL>(
+        ". . 2010012601 0 4294967296 0 0");
+    checkFromBadTexxt<InvalidRRTTL, InvalidRRTTL>(". . 2010012601 0 0 bad 0");
+    checkFromBadTexxt<InvalidRRTTL, InvalidRRTTL>(
+        ". . 2010012601 0 0 4294967296 0");
+    checkFromBadTexxt<InvalidRRTTL, InvalidRRTTL>(". . 2010012601 0 0 0 bad");
+    checkFromBadTexxt<InvalidRRTTL, InvalidRRTTL>(
+        ". . 2010012601 0 0 0 4294967296");
+
+    // No space between RNAME and serial.  This case is the same as missing
+    // M/RNAME.
+    checkFromBadTexxt<MissingNameOrigin, MasterLexer::LexerError>(
+        ". example.0 0 0 0 0", &Name::ROOT_NAME());
+
+    // Extra parameter.  string version immediately detects the error.
+    EXPECT_THROW(generic::SOA soa(". . 0 0 0 0 0 extra"), InvalidRdataText);
+    // Likewise.  Redundant newline is also considered an error.
+    EXPECT_THROW(generic::SOA soa(". . 0 0 0 0 0\n"), InvalidRdataText);
+    EXPECT_THROW(generic::SOA soa("\n. . 0 0 0 0 0"), InvalidRdataText);
+    // lexer version defers the check to the upper layer (we pass origin
+    // to skip the check with the string version).
+    checkFromText("ns root 2010012601 1H 5M 1000H 20M extra", &origin);
 }
 
 TEST_F(Rdata_SOA_Test, createFromWire) {
@@ -97,4 +211,42 @@ TEST_F(Rdata_SOA_Test, getMinimum) {
                                         0, 0, 0, 0, 0x80706050).getMinimum());
 }
 
+void
+compareCheck(const generic::SOA& small, const generic::SOA& large) {
+    EXPECT_GT(0, small.compare(large));
+    EXPECT_LT(0, large.compare(small));
+}
+
+TEST_F(Rdata_SOA_Test, compare) {
+    // Check simple equivalence
+    EXPECT_EQ(0, rdata_soa.compare(generic::SOA(
+                                       "ns.example.com. root.example.com. "
+                                       "2010012601 3600 300 3600000 1200")));
+    // Check name comparison is case insensitive
+    EXPECT_EQ(0, rdata_soa.compare(generic::SOA(
+                                       "NS.example.com. root.EXAMPLE.com. "
+                                       "2010012601 3600 300 3600000 1200")));
+
+    // Check names are compared in the RDATA comparison semantics (different
+    // from DNSSEC ordering for owner names)
+    compareCheck(generic::SOA("a.example. . 0 0 0 0 0"),
+                 generic::SOA("example. . 0 0 0 0 0"));
+    compareCheck(generic::SOA(". a.example. 0 0 0 0 0"),
+                 generic::SOA(". example. 0 0 0 0 0"));
+
+    // Compare other numeric fields: 1076895760 = 0x40302010,
+    // 270544960 = 0x10203040.  These are chosen to make sure that machine
+    // endian doesn't confuse the comparison results.
+    compareCheck(generic::SOA(". . 270544960 0 0 0 0"),
+                 generic::SOA(". . 1076895760 0 0 0 0"));
+    compareCheck(generic::SOA(". . 0 270544960 0 0 0"),
+                 generic::SOA(". . 0 1076895760 0 0 0"));
+    compareCheck(generic::SOA(". . 0 0 270544960 0 0"),
+                 generic::SOA(". . 0 0 1076895760 0 0"));
+    compareCheck(generic::SOA(". . 0 0 0 270544960 0"),
+                 generic::SOA(". . 0 0 0 1076895760 0"));
+    compareCheck(generic::SOA(". . 0 0 0 0 270544960"),
+                 generic::SOA(". . 0 0 0 0 1076895760"));
+}
+
 }
diff --git a/src/lib/dns/tests/rdata_txt_like_unittest.cc b/src/lib/dns/tests/rdata_txt_like_unittest.cc
index ef9bdfe..cb3c44d 100644
--- a/src/lib/dns/tests/rdata_txt_like_unittest.cc
+++ b/src/lib/dns/tests/rdata_txt_like_unittest.cc
@@ -57,7 +57,6 @@ template<class TXT_LIKE>
 class Rdata_TXT_LIKE_Test : public RdataTest {
 protected:
     Rdata_TXT_LIKE_Test() :
-        loader_cb(MasterLoaderCallbacks::getNullCallbacks()),
         wiredata_longesttxt(256, 'a'),
         rdata_txt_like("Test-String"),
         rdata_txt_like_empty("\"\""),
@@ -67,7 +66,6 @@ protected:
     }
 
 protected:
-    MasterLoaderCallbacks loader_cb;
     vector<uint8_t> wiredata_longesttxt;
     const TXT_LIKE rdata_txt_like;
     const TXT_LIKE rdata_txt_like_empty;
diff --git a/src/lib/dns/tests/rdata_unittest.cc b/src/lib/dns/tests/rdata_unittest.cc
index 95f50e7..67eae2f 100644
--- a/src/lib/dns/tests/rdata_unittest.cc
+++ b/src/lib/dns/tests/rdata_unittest.cc
@@ -41,7 +41,8 @@ namespace isc {
 namespace dns {
 namespace rdata {
 RdataTest::RdataTest() :
-    obuffer(0), rdata_nomatch(createRdata(RRType(0), RRClass(1), "\\# 0"))
+    obuffer(0), rdata_nomatch(createRdata(RRType(0), RRClass(1), "\\# 0")),
+    loader_cb(MasterLoaderCallbacks::getNullCallbacks())
 {}
 
 RdataPtr
diff --git a/src/lib/dns/tests/rdata_unittest.h b/src/lib/dns/tests/rdata_unittest.h
index af19311..3f1dbb3 100644
--- a/src/lib/dns/tests/rdata_unittest.h
+++ b/src/lib/dns/tests/rdata_unittest.h
@@ -42,6 +42,7 @@ protected:
     /// used to test the compare() method against a well-known RR type.
     RdataPtr rdata_nomatch;
     MasterLexer lexer;
+    MasterLoaderCallbacks loader_cb;
 };
 
 namespace test {



More information about the bind10-changes mailing list