Commit 570fc148 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[2976] Completed implementation of fromWire test.

parent 010bda2e
......@@ -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
......
......@@ -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
......
......@@ -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_;
};
......
// 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
// 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
......@@ -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)
......
// 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
......
// 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
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment