BIND 10 trac2312, updated. a6c3266fe1acdfa5393f1cd2aa2a502615800943 [2312] Unit tests to validate custom options for different definitions.
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Nov 27 10:06:39 UTC 2012
The branch, trac2312 has been updated
via a6c3266fe1acdfa5393f1cd2aa2a502615800943 (commit)
via c02e37894d858a0c3f70deb90ffba14c0ae58b54 (commit)
from f47316a1d2b49791b785cf7b8b5e11a13a7a0fbe (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 a6c3266fe1acdfa5393f1cd2aa2a502615800943
Author: Marcin Siodelski <marcin at isc.org>
Date: Tue Nov 27 11:06:29 2012 +0100
[2312] Unit tests to validate custom options for different definitions.
commit c02e37894d858a0c3f70deb90ffba14c0ae58b54
Author: Marcin Siodelski <marcin at isc.org>
Date: Tue Nov 27 08:26:44 2012 +0100
[2312] Swap the custom option buffers when all initialized.
-----------------------------------------------------------------------
Summary of changes:
src/lib/dhcp/option_custom.cc | 44 ++--
src/lib/dhcp/option_custom.h | 4 +-
src/lib/dhcp/tests/option_custom_unittest.cc | 341 ++++++++++++++++++++++++--
3 files changed, 339 insertions(+), 50 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/lib/dhcp/option_custom.cc b/src/lib/dhcp/option_custom.cc
index 3b85474..a6747f2 100644
--- a/src/lib/dhcp/option_custom.cc
+++ b/src/lib/dhcp/option_custom.cc
@@ -23,13 +23,8 @@ OptionCustom::OptionCustom(const OptionDefinition& def,
Universe u,
const OptionBuffer& data)
: Option(u, def.getCode(), data.begin(), data.end()),
- definition_(def),
- init_passed_(true) {
- try {
- createBuffers();
- } catch (const Exception& ex) {
- init_passed_ = false;
- }
+ definition_(def) {
+ createBuffers();
}
OptionCustom::OptionCustom(const OptionDefinition& def,
@@ -37,13 +32,8 @@ OptionCustom::OptionCustom(const OptionDefinition& def,
OptionBufferConstIter first,
OptionBufferConstIter last)
: Option(u, def.getCode(), first, last),
- definition_(def),
- init_passed_(true) {
- try {
- createBuffers();
- } catch (const Exception& ex) {
- init_passed_ = false;
- }
+ definition_(def) {
+ createBuffers();
}
void
@@ -80,7 +70,7 @@ OptionCustom::createBuffers() {
if (data_size == 0) {
isc_throw(OutOfRange, "option buffer truncated");
}
- buffers_.push_back(OptionBuffer(data, data + data_size));
+ buffers.push_back(OptionBuffer(data, data + data_size));
data += data_size;
}
} else {
@@ -103,23 +93,24 @@ OptionCustom::createBuffers() {
// have checked this already.
assert(data_size > 0);
do {
- buffers_.push_back(OptionBuffer(data, data + data_size));
+ buffers.push_back(OptionBuffer(data, data + data_size));
data += data_size;
} while (std::distance(data, data_.end()) >= data_size);
} else {
if (data_size == 0) {
data_size = std::distance(data, data_.end());
}
- buffers_.push_back(OptionBuffer(data, data + data_size));
+ buffers.push_back(OptionBuffer(data, data + data_size));
}
}
+ std::swap(buffers_, buffers);
}
void
OptionCustom::pack4(isc::util::OutputBuffer& buf) {
if (len() > 255) {
- isc_throw(OutOfRange, "DHCPv4 Option " << type_ << " is too big."
- << " At most 255 bytes are supported.");
+ isc_throw(OutOfRange, "DHCPv4 Option " << type_
+ << " value is too high. At most 255 is supported.");
}
buf.writeUint8(type_);
@@ -153,6 +144,12 @@ OptionCustom::readAddress(const uint32_t index, asiolink::IOAddress& address) co
}
}
+const OptionBuffer&
+OptionCustom::readBinary(const uint32_t index) const {
+ checkIndex(index);
+ return (buffers_[index]);
+}
+
bool
OptionCustom::readBoolean(const uint32_t index) const {
checkIndex(index);
@@ -194,12 +191,7 @@ OptionCustom::len() {
bool
OptionCustom::valid() {
- if ((universe_ != V4 && universe_ != V6) ||
- !init_passed_) {
- return (false);
- }
-
- return (true);
+ return (Option::valid());
}
std::string OptionCustom::toText(int /* =0 */ ) {
@@ -232,6 +224,8 @@ void OptionCustom::setData(const OptionBufferConstIter first,
// We will copy entire option buffer, so we have to resize data_.
data_.resize(std::distance(first, last));
std::copy(first, last, data_.begin());
+
+ createBuffers();
}
} // end of isc::dhcp namespace
diff --git a/src/lib/dhcp/option_custom.h b/src/lib/dhcp/option_custom.h
index 6721adf..d0c9a4d 100644
--- a/src/lib/dhcp/option_custom.h
+++ b/src/lib/dhcp/option_custom.h
@@ -77,6 +77,8 @@ public:
void readAddress(const uint32_t index, asiolink::IOAddress& address) const;
+ const OptionBuffer& readBinary(const uint32_t index) const;
+
bool readBoolean(const uint32_t index) const;
template<typename T>
@@ -173,8 +175,6 @@ private:
OptionDefinition definition_;
- bool init_passed_;
-
std::vector<OptionBuffer> buffers_;
};
diff --git a/src/lib/dhcp/tests/option_custom_unittest.cc b/src/lib/dhcp/tests/option_custom_unittest.cc
index b6bfaf3..e2edd54 100644
--- a/src/lib/dhcp/tests/option_custom_unittest.cc
+++ b/src/lib/dhcp/tests/option_custom_unittest.cc
@@ -16,6 +16,8 @@
#include <asiolink/io_address.h>
#include <dhcp/option_custom.h>
+
+#include <boost/scoped_ptr.hpp>
#include <gtest/gtest.h>
using namespace isc;
@@ -28,11 +30,7 @@ namespace {
class OptionCustomTest : public ::testing::Test {
public:
/// @brief Constructor.
- OptionCustomTest() {
- for (int i = 0; i < 255; ++i) {
- buf_.push_back(i);
- }
- }
+ OptionCustomTest() { }
void writeAddress(const asiolink::IOAddress& address,
std::vector<uint8_t>& buf) {
@@ -61,8 +59,6 @@ public:
std::copy_backward(value.c_str(), value.c_str() + value.size(),
buf.end());
}
-
- OptionBuffer buf_;
};
TEST_F(OptionCustomTest, constructor) {
@@ -70,44 +66,326 @@ TEST_F(OptionCustomTest, constructor) {
ASSERT_THROW(opt_def1.validate(), isc::Exception); */
}
-TEST_F(OptionCustomTest, setData) {
+// The purpose of this test is to verify that 'empty' option definition can
+// be used to create an instance of custom option.
+TEST_F(OptionCustomTest, emptyData) {
+ OptionDefinition opt_def("OPTION_FOO", 232, "empty");
+
+ boost::scoped_ptr<OptionCustom> option;
+ ASSERT_NO_THROW(
+ option.reset(new OptionCustom(opt_def, Option::V4, OptionBuffer()));
+ );
+ ASSERT_TRUE(option);
+}
+
+// The purpose of this test is to verify that the option definition comprising
+// a binary value can be used to create an instance of custom option.
+TEST_F(OptionCustomTest, binaryData) {
+ OptionDefinition opt_def("OPTION_FOO", 231, "binary");
+
+ // Create a buffer holding some binary data. This data will be
+ // used as reference when we read back the data from a created
+ // option.
+ OptionBuffer buf_in(14);
+ for (int i = 0; i < 14; ++i) {
+ buf_in[i] = i;
+ }
+ // Use scoped pointer because it allows to declare the option
+ // in the function scope and initialize it under ASSERT.
+ boost::scoped_ptr<OptionCustom> option;
+ // Custom option may throw exception if the provided buffer is
+ // malformed.
+ ASSERT_NO_THROW(
+ option.reset(new OptionCustom(opt_def, Option::V4, buf_in));
+ );
+ ASSERT_TRUE(option);
+
+ // The custom option should hold just one buffer that can be
+ // accessed using index 0.
+ OptionBuffer buf_out;
+ ASSERT_NO_THROW(buf_out = option->readBinary(0));
+
+ // Read buffer must match exactly with the buffer used to
+ // create option instance.
+ ASSERT_EQ(buf_in.size(), buf_out.size());
+ EXPECT_TRUE(std::equal(buf_in.begin(), buf_in.end(), buf_out.begin()));
+}
+
+// The purpose of this test is to verify that the option definition comprising
+// single boolean value can be used to create an instance of custom option.
+TEST_F(OptionCustomTest, booleanData) {
+ OptionDefinition opt_def("OPTION_FOO", 1000, "boolean");
+
+ OptionBuffer buf;
+ // Push back the value that represents 'false'.
+ buf.push_back(0);
+ // Push back the 'true' value. Note that this value should
+ // be ignored by custom option because it holds single boolean
+ // value (according to option definition).
+ buf.push_back(1);
+
+ boost::scoped_ptr<OptionCustom> option;
+ ASSERT_NO_THROW(
+ option.reset(new OptionCustom(opt_def, Option::V6, buf));
+ );
+ ASSERT_TRUE(option);
+
+ // Initialize the value to true because we want to make sure
+ // that it is modified to 'false' by readBoolean below.
+ bool value = true;
+
+ // Read the boolean value from only one available buffer indexed
+ // with 0. It is expected to be 'false'.
+ ASSERT_NO_THROW(value = option->readBoolean(0));
+ EXPECT_FALSE(value);
+}
+
+// The purpose of this test is to verify that the option definition comprising
+// 16-bit signed integer value can be used to create an instance of custom option.
+TEST_F(OptionCustomTest, int16Data) {
+ OptionDefinition opt_def("OPTION_FOO", 1000, "int16");
+
+ OptionBuffer buf;
+ // Store signed integer value in the input buffer.
+ writeInt<int16_t>(-234, buf);
+
+ // Create custom option.
+ boost::scoped_ptr<OptionCustom> option;
+ ASSERT_NO_THROW(
+ option.reset(new OptionCustom(opt_def, Option::V6, buf));
+ );
+ ASSERT_TRUE(option);
+
+ // Initialize value to 0 explicitely to make sure that is
+ // modified by readInteger function to expected -234.
+ int16_t value = 0;
+ ASSERT_NO_THROW(value = option->readInteger<int16_t>(0));
+ EXPECT_EQ(-234, value);
+}
+
+// The purpose of this test is to verify that the option definition comprising
+// single IPv4 addres can be used to create an instance of custom option.
+TEST_F(OptionCustomTest, ipv4AddressData) {
+ OptionDefinition opt_def("OPTION_FOO", 231, "ipv4-address");
+
+ // Create input buffer.
+ OptionBuffer buf;
+ writeAddress(IOAddress("192.168.100.50"), buf);
+
+ // Create custom option.
+ boost::scoped_ptr<OptionCustom> option;
+ ASSERT_NO_THROW(
+ option.reset(new OptionCustom(opt_def, Option::V4, buf));
+ );
+ ASSERT_TRUE(option);
+
+ IOAddress address("127.0.0.1");
+ // Read IPv4 address from using index 0.
+ ASSERT_NO_THROW(option->readAddress(0, address));
+
+ EXPECT_EQ("192.168.100.50", address.toText());
+}
+
+// The purpose of this test is to verify that the option definition comprising
+// single IPv6 addres can be used to create an instance of custom option.
+TEST_F(OptionCustomTest, ipv6AddressData) {
+ OptionDefinition opt_def("OPTION_FOO", 1000, "ipv6-address");
+
+ // Initialize input buffer.
+ OptionBuffer buf;
+ writeAddress(IOAddress("2001:db8:1::100"), buf);
+
+ // Create custom option using input buffer.
+ boost::scoped_ptr<OptionCustom> option;
+ ASSERT_NO_THROW(
+ option.reset(new OptionCustom(opt_def, Option::V6, buf));
+ );
+ ASSERT_TRUE(option);
+
+ // Custom option should comprise exactly one buffer that represents
+ // IPv6 address.
+ IOAddress address("::1");
+ // Read an address from buffer #0.
+ ASSERT_NO_THROW(option->readAddress(0, address));
+
+ EXPECT_EQ("2001:db8:1::100", address.toText());
+}
+
+// The purpose of this test is to verify that the option definition comprising
+// string value can be used to create an instance of custom option.
+TEST_F(OptionCustomTest, stringData) {
OptionDefinition opt_def("OPTION_FOO", 1000, "string");
+ // Create an input buffer holding some string value.
OptionBuffer buf;
writeString("hello world!", buf);
- OptionCustom option(opt_def, Option::V6, buf.begin(), buf.end());
- ASSERT_TRUE(option.valid());
+ // Create custom option using input buffer.
+ boost::scoped_ptr<OptionCustom> option;
+ ASSERT_NO_THROW(
+ option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end()));
+ );
+ ASSERT_TRUE(option);
+
+ // Custom option should now comprise single string value that
+ // can be accessed using index 0.
std::string value;
- ASSERT_NO_THROW(option.readString(0, value));
+ ASSERT_NO_THROW(option->readString(0, value));
EXPECT_EQ("hello world!", value);
}
-TEST_F(OptionCustomTest, setArrayData) {
+// The purpose of this test is to verify that the option definition comprising
+// an array of boolean values can be used to create an instance of custom option.
+TEST_F(OptionCustomTest, booleanDataArray) {
+ OptionDefinition opt_def("OPTION_FOO", 1000, "boolean", true);
+
+ // Create a buffer with 5 values that represent array of
+ // booleans.
+ OptionBuffer buf(5);
+ buf[0] = 1; // true
+ buf[1] = 0; // false
+ buf[2] = 0; // false
+ buf[3] = 1; // true
+ buf[4] = 1; // true
+
+ // Use the input buffer to create custom option.
+ boost::scoped_ptr<OptionCustom> option;
+ ASSERT_NO_THROW(
+ option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end()));
+ );
+ ASSERT_TRUE(option);
+
+ // Read values from custom option using indexes 0..4 and
+ // check that they are valid.
+ bool value0 = false;
+ ASSERT_NO_THROW(value0 = option->readBoolean(0));
+ EXPECT_TRUE(value0);
+
+ bool value1 = true;
+ ASSERT_NO_THROW(value1 = option->readBoolean(1));
+ EXPECT_FALSE(value1);
+
+ bool value2 = true;
+ ASSERT_NO_THROW(value2 = option->readBoolean(2));
+ EXPECT_FALSE(value2);
+
+ bool value3 = false;
+ ASSERT_NO_THROW(value3 = option->readBoolean(3));
+ EXPECT_TRUE(value3);
+
+ bool value4 = false;
+ ASSERT_NO_THROW(value4 = option->readBoolean(4));
+ EXPECT_TRUE(value4);
+}
+
+// The purpose of this test is to verify that the option definition comprising
+// an array of 32-bit signed integer values can be used to create an instance
+// of custom option.
+TEST_F(OptionCustomTest, uint32DataArray) {
OptionDefinition opt_def("OPTION_FOO", 1000, "uint32", true);
+ // Create an input buffer that holds 4 uint32 values that
+ // represent an array.
std::vector<uint32_t> values;
values.push_back(71234);
values.push_back(12234);
values.push_back(54362);
values.push_back(1234);
+ // Store these values in a buffer.
OptionBuffer buf;
for (int i = 0; i < values.size(); ++i) {
writeInt<uint32_t>(values[i], buf);
}
- OptionCustom option(opt_def, Option::V6, buf.begin(), buf.begin() + 13);
- ASSERT_TRUE(option.valid());
+ // Create custom option using the input buffer.
+ boost::scoped_ptr<OptionCustom> option;
+ ASSERT_NO_THROW(
+ // Note that we just use a part of the whole buffer here: 13 bytes. We want to
+ // check that buffer length which is non-divisible by 4 (size of uint32_t) is
+ // accepted and only 3 (instead of 4) elements will be stored in a custom option.
+ option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.begin() + 13));
+ );
+ ASSERT_TRUE(option);
+ // Expect only 3 values.
for (int i = 0; i < 3; ++i) {
uint32_t value = 0;
- ASSERT_NO_THROW(value = option.readInteger<uint32_t>(i));
+ ASSERT_NO_THROW(value = option->readInteger<uint32_t>(i));
EXPECT_EQ(values[i], value);
}
}
-TEST_F(OptionCustomTest, setRecordData) {
+// The purpose of this test is to verify that the option definition comprising
+// an array of IPv4 addresses can be used to create an instance of custom option.
+TEST_F(OptionCustomTest, ipv4AddressDataArray) {
+ OptionDefinition opt_def("OPTION_FOO", 231, "ipv4-address", true);
+
+ // Initialize reference data.
+ std::vector<IOAddress> addresses;
+ addresses.push_back(IOAddress("192.168.0.1"));
+ addresses.push_back(IOAddress("127.0.0.1"));
+ addresses.push_back(IOAddress("10.10.1.2"));
+
+ // Store the collection of IPv4 addresses into the buffer.
+ OptionBuffer buf;
+ for (int i = 0; i < addresses.size(); ++i) {
+ writeAddress(addresses[i], buf);
+ }
+
+ // Use the input buffer to create custom option.
+ boost::scoped_ptr<OptionCustom> option;
+ ASSERT_NO_THROW(
+ option.reset(new OptionCustom(opt_def, Option::V4, buf.begin(), buf.begin() + 13));
+ );
+ ASSERT_TRUE(option);
+
+ // We expect 3 IPv4 addresses being stored in the option.
+ for (int i = 0; i < 3; ++i) {
+ IOAddress address("10.10.10.10");
+ ASSERT_NO_THROW(option->readAddress(i, address));
+ EXPECT_EQ(addresses[i].toText(), address.toText());
+ }
+}
+
+// The purpose of this test is to verify that the option definition comprising
+// an array of IPv6 addresses can be used to create an instance of custom option.
+TEST_F(OptionCustomTest, ipv6AddressDataArray) {
+ OptionDefinition opt_def("OPTION_FOO", 1000, "ipv6-address", true);
+
+ // Initialize reference data.
+ std::vector<IOAddress> addresses;
+ addresses.push_back(IOAddress("2001:db8:1::3"));
+ addresses.push_back(IOAddress("::1"));
+ addresses.push_back(IOAddress("fe80::3"));
+
+ // Store the collection of IPv6 addresses into the buffer.
+ OptionBuffer buf;
+ for (int i = 0; i < addresses.size(); ++i) {
+ writeAddress(addresses[i], buf);
+ }
+
+ // Use the input buffer to create custom option.
+ boost::scoped_ptr<OptionCustom> option;
+ ASSERT_NO_THROW(
+ option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.begin() + 70));
+ );
+ ASSERT_TRUE(option);
+
+ // We expect 3 IPv6 addresses being stored in the option.
+ for (int i = 0; i < 3; ++i) {
+ IOAddress address("fe80::4");
+ ASSERT_NO_THROW(option->readAddress(i, address));
+ EXPECT_EQ(addresses[i].toText(), address.toText());
+ }
+}
+
+// The purpose of this test is to verify that the option definition comprising
+// a record of various data fields can be used to create an instance of
+// custom option.
+TEST_F(OptionCustomTest, recordData) {
+ // Create the definition of an option which comprises
+ // a record of fields of different types.
OptionDefinition opt_def("OPTION_FOO", 1000, "record");
ASSERT_NO_THROW(opt_def.addRecordField("uint16"));
ASSERT_NO_THROW(opt_def.addRecordField("boolean"));
@@ -116,29 +394,46 @@ TEST_F(OptionCustomTest, setRecordData) {
ASSERT_NO_THROW(opt_def.addRecordField("string"));
OptionBuffer buf;
+ // Initialize field 0.
writeInt<uint16_t>(8712, buf);
+ // Initialize field 1 to 'true'
buf.push_back(static_cast<unsigned short>(1));
+ // Initialize field 2 to IPv4 address.
writeAddress(IOAddress("192.168.0.1"), buf);
+ // Initialize field 3 to IPv6 address.
writeAddress(IOAddress("2001:db8:1::1"), buf);
+ // Initialize field 4 to string value.
writeString("ABCD", buf);
- OptionCustom option(opt_def, Option::V6, buf.begin(), buf.begin() + 27);
- ASSERT_TRUE(option.valid());
+ boost::scoped_ptr<OptionCustom> option;
+ ASSERT_NO_THROW(
+ option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.begin() + 27));
+ );
+ ASSERT_TRUE(option);
+ // Verify value in the field 0.
uint16_t value0 = 0;
- ASSERT_NO_THROW(value0 = option.readInteger<uint16_t>(0));
+ ASSERT_NO_THROW(value0 = option->readInteger<uint16_t>(0));
EXPECT_EQ(8712, value0);
+
+ // Verify value in the field 1.
bool value1 = false;
- ASSERT_NO_THROW(value1 = option.readBoolean(1));
+ ASSERT_NO_THROW(value1 = option->readBoolean(1));
EXPECT_TRUE(value1);
+
+ // Verify value in the field 2.
IOAddress value2("127.0.0.1");
- ASSERT_NO_THROW(option.readAddress(2, value2));
+ ASSERT_NO_THROW(option->readAddress(2, value2));
EXPECT_EQ("192.168.0.1", value2.toText());
+
+ // Verify value in the field 3.
IOAddress value3("::1");
- ASSERT_NO_THROW(option.readAddress(3, value3));
+ ASSERT_NO_THROW(option->readAddress(3, value3));
EXPECT_EQ("2001:db8:1::1", value3.toText());
+
+ // Verify value in the field 4.
std::string value4;
- ASSERT_NO_THROW(option.readString(4, value4));
+ ASSERT_NO_THROW(option->readString(4, value4));
EXPECT_EQ("ABCD", value4);
}
More information about the bind10-changes
mailing list