Parcourir la source

[2976] Completed implementation of fromWire test.

Marcin Siodelski il y a 12 ans
Parent
commit
570fc14873

+ 1 - 0
src/bin/d2/Makefile.am

@@ -53,6 +53,7 @@ b10_dhcp_ddns_SOURCES += d2_process.cc d2_process.h
 b10_dhcp_ddns_SOURCES += d_controller.cc d_controller.h
 b10_dhcp_ddns_SOURCES += d2_controller.cc d2_controller.h
 b10_dhcp_ddns_SOURCES += d2_update_message.cc d2_update_message.h
+b10_dhcp_ddns_SOURCES += d2_zone.cc d2_zone.h
 
 nodist_b10_dhcp_ddns_SOURCES = d2_messages.h d2_messages.cc
 EXTRA_DIST += d2_messages.mes

+ 18 - 3
src/bin/d2/d2_update_message.cc

@@ -12,13 +12,12 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <d2/d2_update_message.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/opcode.h>
 #include <dns/question.h>
 
-#include <d2/d2_update_message.h>
-
 namespace isc {
 namespace d2 {
 
@@ -85,7 +84,14 @@ D2UpdateMessage::setZone(const Name& zone, const RRClass& rrclass) {
         message_.clearSection(dns::Message::SECTION_QUESTION);
     }
 
-    message_.addQuestion(Question(zone, rrclass, RRType::SOA()));
+    Question question(zone, rrclass, RRType::SOA());
+    message_.addQuestion(question);
+    zone_.reset(new D2Zone(question.getName(), question.getClass()));
+}
+
+D2ZonePtr
+D2UpdateMessage::getZone() const {
+    return (zone_);
 }
 
 void
@@ -118,6 +124,15 @@ D2UpdateMessage::toWire(AbstractMessageRenderer& renderer) {
 void
 D2UpdateMessage::fromWire(isc::util::InputBuffer& buffer) {
     message_.fromWire(buffer);
+    if (getRRCount(D2UpdateMessage::SECTION_ZONE) > 0) {
+        QuestionPtr question = *message_.beginQuestion();
+        assert(question);
+        zone_.reset(new D2Zone(question->getName(), question->getClass()));
+
+    } else {
+        zone_.reset();
+
+    }
 }
 
 dns::Message::Section

+ 4 - 4
src/bin/d2/d2_update_message.h

@@ -15,6 +15,7 @@
 #ifndef D2_UPDATE_MESSAGE_H
 #define D2_UPDATE_MESSAGE_H
 
+#include <d2/d2_zone.h>
 #include <dns/message.h>
 #include <dns/name.h>
 #include <dns/rcode.h>
@@ -91,16 +92,14 @@ public:
 
     unsigned int getRRCount(const UpdateMsgSection section) const;
 
-    const dns::QuestionIterator beginQuestion() const;
-
-    const dns::QuestionIterator endQuestion() const;
-
     const dns::RRsetIterator beginSection(const UpdateMsgSection section) const;
 
     const dns::RRsetIterator endSection(const UpdateMsgSection section) const;
 
     void setZone(const dns::Name& zone, const dns::RRClass& rrclass);
 
+    D2ZonePtr getZone() const;
+
     void addRRset(const UpdateMsgSection section, const dns::RRsetPtr& rrset);
 
     bool hasRRset(const UpdateMsgSection section, const dns::Name& name,
@@ -122,6 +121,7 @@ private:
     static dns::Message::Section ddnsToDnsSection(const UpdateMsgSection section);
 
     dns::Message message_;
+    D2ZonePtr zone_;
 
 };
 

+ 36 - 0
src/bin/d2/d2_zone.cc

@@ -0,0 +1,36 @@
+// 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.
+
+#include <d2/d2_zone.h>
+
+namespace isc {
+namespace d2 {
+
+D2Zone::D2Zone(const dns::Name& name, const dns::RRClass& rrclass)
+    : name_(name), rrclass_(rrclass) {
+}
+
+std::string D2Zone::toText() const {
+    return (name_.toText() + " " + rrclass_.toText() + " SOA\n");
+}
+
+std::ostream&
+operator<<(std::ostream& os, const D2Zone& zone) {
+    os << zone.toText();
+    return (os);
+}
+
+} // namespace d2
+} // namespace isc
+

+ 115 - 0
src/bin/d2/d2_zone.h

@@ -0,0 +1,115 @@
+// 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 D2_ZONE_H
+#define D2_ZONE_H
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+
+#include <boost/shared_ptr.hpp>
+
+namespace isc {
+namespace d2 {
+
+/// @brief The @c D2Zone encapsulates the Zone section in DNS Update message.
+///
+/// This class is used by the @c D2UpdateMessage to encapsulate the Zone section
+/// of the DNS Update message. Class members hold corresponding values of
+/// section's fields: NAME, CLASS. This class does not hold the RTYPE field value
+/// because RTYPE is always equal to SOA for DNS Update message (see RFC 2136,
+/// section 2.3).
+///
+/// Note, that this @c D2Zone class neither exposes functions to decode messages
+/// from wire format nor to encode to wire format. This is not needed because
+/// @c isc::d2::D2UpdateMessage class uses @c D2Zone only to return the parsed Zone
+/// information to the caller. Internally, D2UpdateMessage parses and stores Zone
+/// section using @c isc::dns::Question class.
+class D2Zone {
+public:
+    /// @brief Constructor from Name and RRClass.
+    ///
+    /// @param name The name of the Zone.
+    /// @param rrclass The RR class of the Zone.
+    D2Zone(const dns::Name& name, const dns::RRClass& rrclass);
+
+    ///
+    /// @name Getters
+    ///
+    //@{
+    /// @brief Returns the Zone name.
+    ///
+    /// @return A reference to the Zone name.
+    const dns::Name& getName() const { return (name_); }
+
+    /// @brief Returns the Zone class.
+    ///
+    /// @return A reference to the Zone class.
+    const dns::RRClass& getClass() const { return (rrclass_); }
+    //@}
+
+    /// @brief Returns text representation of the Zone.
+    ///
+    /// This function concatenates the name of the Zone, Class and Type.
+    /// The type is always SOA.
+    ///
+    /// @return A text representation of the Zone.
+    std::string toText() const;
+
+    ///
+    /// @name Comparison Operators
+    ///
+    //@{
+    /// @brief Equality operator to compare @c D2Zone objects in query and response
+    /// messages.
+    ///
+    /// @param rhs Zone to compare against.
+    ///
+    /// @return true if name and class are equal, false otherwise.
+    bool operator==(const D2Zone& rhs) const {
+        return ((rrclass_ == rhs.rrclass_) && (name_ == rhs.name_));
+    }
+
+    /// @brief Inequality operator to compare @c D2Zone objects in query and
+    /// response messages.
+    ///
+    /// @param rhs Zone to compare against.
+    ///
+    /// @return true if any of name or class are unequal, false otherwise.
+    bool operator!=(const D2Zone& rhs) const {
+        return (!operator==(rhs));
+    }
+    //@}
+
+private:
+    dns::Name name_;       ///< Holds the Zone name.
+    dns::RRClass rrclass_; ///< Holds the Zone class.
+};
+
+typedef boost::shared_ptr<D2Zone> D2ZonePtr;
+
+/// @brief Insert the @c D2Zone as a string into stream.
+///
+/// @param os A @c std::ostream object on which the insertion operation is
+/// performed.
+/// @param zone A reference to the @c D2Zone object output by the
+/// operation.
+/// @param A reference to the same @c std::ostream object referenced by
+/// parameter @c os after the insertion operation.
+std::ostream& operator<<(std::ostream& os, const D2Zone& zone);
+
+} // namespace d2
+} // namespace isc
+
+#endif // D2_ZONE_H

+ 2 - 0
src/bin/d2/tests/Makefile.am

@@ -57,12 +57,14 @@ d2_unittests_SOURCES += ../d_controller.cc ../d2_controller.h
 d2_unittests_SOURCES += ../d2_process.cc ../d2_process.h
 d2_unittests_SOURCES += ../d2_controller.cc ../d2_controller.h
 d2_unittests_SOURCES += ../d2_update_message.cc ../d2_update_message.h
+d2_unittests_SOURCES += ../d2_zone.cc ../d2_zone.h
 d2_unittests_SOURCES += d_test_stubs.cc d_test_stubs.h
 d2_unittests_SOURCES += d2_unittests.cc
 d2_unittests_SOURCES += d2_process_unittests.cc
 d2_unittests_SOURCES += d_controller_unittests.cc
 d2_unittests_SOURCES += d2_controller_unittests.cc
 d2_unittests_SOURCES += d2_update_message_unittests.cc
+d2_unittests_SOURCES += d2_zone_unittests.cc
 nodist_d2_unittests_SOURCES = ../d2_messages.h ../d2_messages.cc
 
 d2_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)

+ 42 - 19
src/bin/d2/tests/d2_update_message_unittests.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// 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
@@ -15,6 +15,7 @@
 #include <config.h>
 
 #include <d2/d2_update_message.h>
+#include <d2/d2_zone.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdataclass.h>
 #include <dns/rdata.h>
@@ -151,50 +152,72 @@ TEST_F(D2UpdateMessageTest, fromWire) {
     };
     InputBuffer buf(bin_msg, sizeof(bin_msg));
 
+    // Create an object to be used to decode the message from the wire format.
     D2UpdateMessage msg(true);
-
+    // Decode the message.
     ASSERT_NO_THROW(msg.fromWire(buf));
 
+    // Check that the message header is valid.
     EXPECT_EQ(0x05AF, msg.getQid());
     EXPECT_EQ(D2UpdateMessage::RESPONSE, msg.getQRFlag());
     EXPECT_EQ(Rcode::YXDOMAIN_CODE, msg.getRcode().getCode());
+
+    // The ZOCOUNT must contain exactly one zone. If it does, we should get
+    // the name, class and type of the zone and verify they are valid.
     ASSERT_EQ(1, msg.getRRCount(D2UpdateMessage::SECTION_ZONE));
-    // Zone section is TBD
+    D2ZonePtr zone = msg.getZone();
+    ASSERT_TRUE(zone);
+    EXPECT_EQ("example.com.", zone->getName().toText());
+    EXPECT_EQ(RRClass::IN().getCode(), zone->getClass().getCode());
 
+    // Check the Prerequisite section. It should contain two records.
     ASSERT_EQ(2, msg.getRRCount(D2UpdateMessage::SECTION_PREREQUISITE));
+
+    // Proceed to the first prerequisite.
     RRsetIterator rrset_it = msg.beginSection(D2UpdateMessage::SECTION_PREREQUISITE);
     RRsetPtr prereq1 = *rrset_it;
     ASSERT_TRUE(prereq1);
-    EXPECT_EQ("foo.example.com.", prereq1->getName().toText());
-    EXPECT_EQ(RRType::AAAA().getCode(), prereq1->getType().getCode());
-    EXPECT_EQ(RRClass::NONE().getCode(), prereq1->getClass().getCode());
-    EXPECT_EQ(0, prereq1->getTTL().getValue());
-    EXPECT_EQ(0, prereq1->getRdataCount());
+    // Check record fields.
+    EXPECT_EQ("foo.example.com.", prereq1->getName().toText()); // NAME
+    EXPECT_EQ(RRType::AAAA().getCode(), prereq1->getType().getCode()); // TYPE
+    EXPECT_EQ(RRClass::NONE().getCode(), prereq1->getClass().getCode()); // CLASS
+    EXPECT_EQ(0, prereq1->getTTL().getValue()); // TTL
+    EXPECT_EQ(0, prereq1->getRdataCount()); // RDLENGTH
 
     // Move to next prerequisite section.
     ++rrset_it;
-
     RRsetPtr prereq2 = *rrset_it;
     ASSERT_TRUE(prereq2);
-    EXPECT_EQ("bar.example.com.", prereq2->getName().toText());
-    EXPECT_EQ(RRType::AAAA().getCode(), prereq2->getType().getCode());
-    EXPECT_EQ(RRClass::ANY().getCode(), prereq2->getClass().getCode());
-    EXPECT_EQ(0, prereq2->getTTL().getValue());
-    EXPECT_EQ(0, prereq2->getRdataCount());
-
+    // Check record fields.
+    EXPECT_EQ("bar.example.com.", prereq2->getName().toText()); // NAME
+    EXPECT_EQ(RRType::AAAA().getCode(), prereq2->getType().getCode()); // TYPE
+    EXPECT_EQ(RRClass::ANY().getCode(), prereq2->getClass().getCode()); // CLASS
+    EXPECT_EQ(0, prereq2->getTTL().getValue()); // TTL
+    EXPECT_EQ(0, prereq2->getRdataCount()); // RDLENGTH
+
+    // Check the Update section. There is only one record, so beginSection()
+    // should return the pointer to this sole record.
     ASSERT_EQ(1, msg.getRRCount(D2UpdateMessage::SECTION_UPDATE));
     rrset_it = msg.beginSection(D2UpdateMessage::SECTION_UPDATE);
     RRsetPtr update = *rrset_it;
     ASSERT_TRUE(update);
-    EXPECT_EQ("foo.example.com.", update->getName().toText());
-    EXPECT_EQ(RRType::AAAA().getCode(), update->getType().getCode());
-    EXPECT_EQ(RRClass::IN().getCode(), update->getClass().getCode());
-    EXPECT_EQ(0xAABBCCDD, update->getTTL().getValue());
+    // Check the record fields.
+    EXPECT_EQ("foo.example.com.", update->getName().toText()); // NAME
+    EXPECT_EQ(RRType::AAAA().getCode(), update->getType().getCode()); // TYPE
+    EXPECT_EQ(RRClass::IN().getCode(), update->getClass().getCode()); // CLASS
+    EXPECT_EQ(0xAABBCCDD, update->getTTL().getValue()); // TTL
+    // There should be exactly one record holding the IPv6 address.
+    // This record can be accessed using RdataIterator. This record
+    // can be compared with the reference record, holding expected IPv6
+    // address using compare function.
     ASSERT_EQ(1, update->getRdataCount());
     RdataIteratorPtr rdata_it = update->getRdataIterator();
     ASSERT_TRUE(rdata_it);
     in::AAAA rdata_ref("2001:db8:1::1");
     EXPECT_EQ(0, rdata_ref.compare(rdata_it->getCurrent()));
+
+    // @todo: at this point we don't test Additional Data records. We may
+    // consider implementing tests for it in the future.
 }
 
 // This test verifies that the wire format of the message is produced

+ 65 - 0
src/bin/d2/tests/d2_zone_unittests.cc

@@ -0,0 +1,65 @@
+// 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.
+
+#include <config.h>
+#include <d2/d2_zone.h>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::d2;
+using namespace isc::dns;
+
+namespace {
+
+TEST(D2ZoneTest, constructor) {
+    D2Zone zone1(Name("example.com"), RRClass::ANY());
+    EXPECT_EQ("example.com.", zone1.getName().toText());
+    EXPECT_EQ(RRClass::ANY().getCode(), zone1.getClass().getCode());
+
+    D2Zone zone2(Name("foo.example.com"), RRClass::IN());
+    EXPECT_EQ("foo.example.com.", zone2.getName().toText());
+    EXPECT_EQ(RRClass::IN().getCode(), zone2.getClass().getCode());
+}
+
+TEST(D2ZoneTest, toText) {
+    D2Zone zone1(Name("example.com"), RRClass::ANY());
+    EXPECT_EQ("example.com. ANY SOA\n", zone1.toText());
+
+    D2Zone zone2(Name("foo.example.com"), RRClass::IN());
+    EXPECT_EQ("foo.example.com. IN SOA\n", zone2.toText());
+}
+
+TEST(D2ZoneTest, compare) {
+    const Name a("a"), b("b");
+    const RRClass in(RRClass::IN()), any(RRClass::ANY());
+
+    // Equality check
+    EXPECT_TRUE(D2Zone(a, any) == D2Zone(a, any));
+    EXPECT_FALSE(D2Zone(a, any) != D2Zone(a, any));
+
+    // Inequality check, objects differ by class.
+    EXPECT_FALSE(D2Zone(a, any) == D2Zone(a, in));
+    EXPECT_TRUE(D2Zone(a, any) != D2Zone(a, in));
+
+    // Inequality check, objects differ by name.
+    EXPECT_FALSE(D2Zone(a, any) == D2Zone(b, any));
+    EXPECT_TRUE(D2Zone(a, any) != D2Zone(b, any));
+
+    // Inequality check, objects differ by name and class.
+    EXPECT_FALSE(D2Zone(a, any) == D2Zone(b, in));
+    EXPECT_TRUE(D2Zone(a, any) != D2Zone(b, in));
+}
+
+} // End of anonymous namespace