From: Marcin Siodelski Date: Tue, 9 Oct 2012 16:34:42 +0000 (+0200) Subject: [2304] Added unit tests for Option6Int option. X-Git-Tag: trac2402_base~5^2~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f4f708e4e93579989bf716d5851311a2b5aff6b5;p=thirdparty%2Fkea.git [2304] Added unit tests for Option6Int option. --- diff --git a/src/lib/dhcp/option6_int.h b/src/lib/dhcp/option6_int.h index 1ecf3dcaf1..e0df4c5f4e 100644 --- a/src/lib/dhcp/option6_int.h +++ b/src/lib/dhcp/option6_int.h @@ -92,6 +92,7 @@ public: default: isc_throw(dhcp::InvalidDataType, "non-numeric type"); } + LibDHCP::packOptions6(buf, options_); } /// @brief Parses received buffer @@ -110,20 +111,26 @@ public: value_ = *begin; break; case 2: - value_ = isc::util::readUint16( &(*begin) ); + value_ = isc::util::readUint16(&(*begin)); break; case 4: - value_ = isc::util::readUint32( &(*begin) ); + value_ = isc::util::readUint32(&(*begin)); break; default: isc_throw(dhcp::InvalidDataType, "non-numeric type"); } - + begin += OptionDataTypes::len; LibDHCP::unpackOptions6(OptionBuffer(begin, end), options_); } + /// @brief Set option value. + /// + /// @param value new option value. void setValue(T value) { value_ = value; } + /// @brief Return option value. + /// + /// @return option value. T getValue() const { return value_; } /// @brief returns complete length of option @@ -144,7 +151,7 @@ public: private: - T value_; ///< Value cabveyed by the option. + T value_; ///< Value cabveyed by the option. }; } // isc::dhcp namespace diff --git a/src/lib/dhcp/tests/Makefile.am b/src/lib/dhcp/tests/Makefile.am index 308d3eba40..e676834c1e 100644 --- a/src/lib/dhcp/tests/Makefile.am +++ b/src/lib/dhcp/tests/Makefile.am @@ -32,6 +32,7 @@ libdhcp___unittests_SOURCES += option6_iaaddr_unittest.cc libdhcp___unittests_SOURCES += option6_ia_unittest.cc libdhcp___unittests_SOURCES += option6_addrlst_unittest.cc libdhcp___unittests_SOURCES += option4_addrlst_unittest.cc +libdhcp___unittests_SOURCES += option6_int_unittest.cc libdhcp___unittests_SOURCES += option_unittest.cc libdhcp___unittests_SOURCES += option_definition_unittest.cc libdhcp___unittests_SOURCES += pkt6_unittest.cc diff --git a/src/lib/dhcp/tests/option6_int_unittest.cc b/src/lib/dhcp/tests/option6_int_unittest.cc new file mode 100644 index 0000000000..fad615d3fe --- /dev/null +++ b/src/lib/dhcp/tests/option6_int_unittest.cc @@ -0,0 +1,329 @@ +// 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace isc; +using namespace isc::dhcp; +using namespace isc::asiolink; +using namespace isc::util; + +namespace { + +/// @brief Option6Int test class. +class Option6IntTest : public ::testing::Test { +public: + /// @brief Constructor. + /// + /// Initializes the option buffer with some data. + Option6IntTest(): buf_(255), out_buf_(255) { + for (int i = 0; i < 255; i++) { + buf_[i] = 255 - i; + } + } + + OptionBuffer buf_; ///< Option buffer + OutputBuffer out_buf_; ///< Output buffer +}; + +/// @todo: below, there is a bunch of tests for options that +/// convey unsigned value. We should maybe extend these tests for +/// signed types too. + +TEST_F(Option6IntTest, useInvalidType) { + EXPECT_THROW( + boost::scoped_ptr >(new Option6Int(D6O_ELAPSED_TIME, 10)), + InvalidDataType + ); + + EXPECT_THROW( + boost::scoped_ptr >(new Option6Int(D6O_ELAPSED_TIME, 10)), + InvalidDataType + ); + +} + +TEST_F(Option6IntTest, basicUint8) { + // Create option that conveys single uint8_t value. + boost::shared_ptr > opt; + // Initialize buffer with this value. + buf_[0] = 0xa1; + // Constructor may throw in case provided buffer is too short. + ASSERT_NO_THROW( + opt = boost::shared_ptr >(new Option6Int(D6O_PREFERENCE, + buf_.begin(), + buf_.end())) + ); + + EXPECT_EQ(Option::V6, opt->getUniverse()); + EXPECT_EQ(D6O_PREFERENCE, opt->getType()); + // Option should return the same value that we initialized the first + // byte of the buffer with. + EXPECT_EQ(buf_[0], opt->getValue()); + + // test for pack() + opt->pack(out_buf_); + + // Data length is 1 byte. + EXPECT_EQ(1, opt->len() - opt->getHeaderLen()); + EXPECT_EQ(D6O_PREFERENCE, opt->getType()); + // The total length is 1 byte for data and 4 bytes for header. + EXPECT_EQ(5, out_buf_.getLength()); + + // Check if pack worked properly: + InputBuffer out(out_buf_.getData(), out_buf_.getLength()); + // if option type is correct + EXPECT_EQ(D6O_PREFERENCE, out.readUint16()); + // if option length is correct + EXPECT_EQ(1, out.readUint16()); + // if data is correct + EXPECT_EQ(0xa1, out.readUint8() ); +} + +TEST_F(Option6IntTest, basicUint16) { + // Create option that conveys single uint16_t value. + boost::shared_ptr > opt; + // Initialize buffer with uint16_t value. + buf_[0] = 0xa1; + buf_[1] = 0xa2; + // Constructor may throw in case provided buffer is too short. + ASSERT_NO_THROW( + opt = boost::shared_ptr >(new Option6Int(D6O_ELAPSED_TIME, + buf_.begin(), + buf_.end())) + ); + + EXPECT_EQ(Option::V6, opt->getUniverse()); + EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType()); + // Option should return the value equal to the contents of first + // and second byte of the buffer. + EXPECT_EQ(0xa1a2, opt->getValue()); + + // Test for pack() + opt->pack(out_buf_); + + // Data length is 2 bytes. + EXPECT_EQ(2, opt->len() - opt->getHeaderLen()); + EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType()); + // The total length is 2 byte for data and 4 bytes for header. + EXPECT_EQ(6, out_buf_.getLength()); + + // Check if pack worked properly: + InputBuffer out(out_buf_.getData(), out_buf_.getLength()); + // if option type is correct + EXPECT_EQ(D6O_ELAPSED_TIME, out.readUint16()); + // if option length is correct + EXPECT_EQ(2, out.readUint16()); + // if data is correct + EXPECT_EQ(0xa1a2, out.readUint16() ); +} + +TEST_F(Option6IntTest, basicUint32) { + // Create option that conveys single uint32_t value. + boost::shared_ptr > opt; + // Initialize buffer with uint32_t value. + buf_[0] = 0xa1; + buf_[1] = 0xa2; + buf_[2] = 0xa3; + buf_[3] = 0xa4; + // Constructor may throw in case provided buffer is too short. + ASSERT_NO_THROW( + opt = boost::shared_ptr >(new Option6Int(D6O_CLT_TIME, + buf_.begin(), + buf_.end())) + ); + + EXPECT_EQ(Option::V6, opt->getUniverse()); + EXPECT_EQ(D6O_CLT_TIME, opt->getType()); + // Option should return the value equal to the value made of + // first 4 bytes of the buffer. + EXPECT_EQ(0xa1a2a3a4, opt->getValue()); + + // Test for pack() + opt->pack(out_buf_); + + // Data length is 4 bytes. + EXPECT_EQ(4, opt->len() - opt->getHeaderLen()); + EXPECT_EQ(D6O_CLT_TIME, opt->getType()); + // The total length is 4 bytes for data and 4 bytes for header. + EXPECT_EQ(8, out_buf_.getLength()); + + // Check if pack worked properly: + InputBuffer out(out_buf_.getData(), out_buf_.getLength()); + // if option type is correct + EXPECT_EQ(D6O_CLT_TIME, out.readUint16()); + // if option length is correct + EXPECT_EQ(4, out.readUint16()); + // if data is correct + EXPECT_EQ(0xa1a2a3a4, out.readUint32()); +} + + +TEST_F(Option6IntTest, simpleUint8) { + boost::shared_ptr > opt(new Option6Int(D6O_PREFERENCE, 123)); + // Check if constructor intitialized the option value correctly. + EXPECT_EQ(123, opt->getValue()); + // Override the value. + opt->setValue(111); + + EXPECT_EQ(Option::V6, opt->getUniverse()); + EXPECT_EQ(D6O_PREFERENCE, opt->getType()); + // Check if the value has been overriden. + EXPECT_EQ(111, opt->getValue()); +} + +TEST_F(Option6IntTest, simpleUint16) { + boost::shared_ptr > opt(new Option6Int(D6O_ELAPSED_TIME, 123)); + // Check if constructor intitialized the option value correctly. + EXPECT_EQ(123, opt->getValue()); + // Override the value. + opt->setValue(0x0102); + + EXPECT_EQ(Option::V6, opt->getUniverse()); + EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType()); + // Check if the value has been overriden. + EXPECT_EQ(0x0102, opt->getValue()); +} + +TEST_F(Option6IntTest, simpleUint32) { + boost::shared_ptr > opt(new Option6Int(D6O_CLT_TIME, 123)); + // Check if constructor intitialized the option value correctly. + EXPECT_EQ(123, opt->getValue()); + // Override the value. + opt->setValue(0x01020304); + + EXPECT_EQ(Option::V6, opt->getUniverse()); + EXPECT_EQ(D6O_CLT_TIME, opt->getType()); + // Check if the value has been overriden. + EXPECT_EQ(0x01020304, opt->getValue()); +} + +TEST_F(Option6IntTest, packSuboptions) { + uint16_t opt_code = 80; + + boost::shared_ptr > opt(new Option6Int(opt_code, 0x01020304)); + OptionPtr sub1(new Option(Option::V6, 0xcafe)); + + boost::shared_ptr addr1( + new Option6IAAddr(D6O_IAADDR, IOAddress("2001:db8:1234:5678::abcd"), 0x5000, 0x7000)); + + opt->addOption(sub1); + opt->addOption(addr1); + + ASSERT_EQ(28, addr1->len()); + ASSERT_EQ(4, sub1->len()); + ASSERT_EQ(40, opt->len()); + + uint8_t expected[] = { + opt_code / 256, opt_code % 256, // type + 0, 36, // length + 0x01, 0x02, 0x03, 0x04, // uint32_t value + + // iaaddr suboption + D6O_IAADDR / 256, D6O_IAADDR % 256, // type + 0, 24, // len + 0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78, + 0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address + 0, 0, 0x50, 0, // preferred-lifetime + 0, 0, 0x70, 0, // valid-lifetime + + // suboption + 0xca, 0xfe, // type + 0, 0 // len + }; + + // Create on-wire format of option and suboptions. + opt->pack(out_buf_); + // Compare the on-wire data with the reference buffer. + ASSERT_EQ(40, out_buf_.getLength()); + EXPECT_EQ(0, memcmp(out_buf_.getData(), expected, 40)); +} + + +TEST_F(Option6IntTest, unpackSuboptions) { + // Create some dummy option. + const uint16_t opt_code = 80; + // Prepare reference data. + uint8_t expected[] = { + opt_code / 256, opt_code % 256, // type + 0, 34, // length + 0x01, 0x02, // uint16_t value + + // iaaddr suboption + D6O_IAADDR / 256, D6O_IAADDR % 256, // type + 0, 24, // len + 0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78, + 0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address + 0, 0, 0x50, 0, // preferred-lifetime + 0, 0, 0x70, 0, // valid-lifetime + + // suboption + 0xca, 0xfe, // type + 0, 0 // len + }; + ASSERT_EQ(38, sizeof(expected)); + + memcpy(&buf_[0], expected, sizeof(expected)); + + boost::shared_ptr > opt; + EXPECT_NO_THROW( + opt = boost::shared_ptr< + Option6Int >(new Option6Int(opt_code, buf_.begin() + 4, + buf_.begin() + sizeof(expected))); + ); + ASSERT_TRUE(opt); + + EXPECT_EQ(opt_code, opt->getType()); + EXPECT_EQ(0x0102, opt->getValue()); + + // Checks for address option + OptionPtr subopt = opt->getOption(D6O_IAADDR); + ASSERT_TRUE(subopt); + boost::shared_ptr addr(boost::dynamic_pointer_cast(subopt)); + ASSERT_TRUE(addr); + + EXPECT_EQ(D6O_IAADDR, addr->getType()); + EXPECT_EQ(28, addr->len()); + EXPECT_EQ(0x5000, addr->getPreferred()); + EXPECT_EQ(0x7000, addr->getValid()); + EXPECT_EQ("2001:db8:1234:5678::abcd", addr->getAddress().toText()); + + // Checks for dummy option + subopt = opt->getOption(0xcafe); + ASSERT_TRUE(subopt); // should be non-NULL + + EXPECT_EQ(0xcafe, subopt->getType()); + EXPECT_EQ(4, subopt->len()); + // There should be no data at all + EXPECT_EQ(0, subopt->getData().size()); + + // Try to get non-existent option. + subopt = opt->getOption(1); + // Expecting NULL which means that option does not exist. + ASSERT_FALSE(subopt); +} + +} // anonymous namespace