diff options
Diffstat (limited to 'src/lib/dhcp/tests/option_opaque_data_tuples_unittest.cc')
-rw-r--r-- | src/lib/dhcp/tests/option_opaque_data_tuples_unittest.cc | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/src/lib/dhcp/tests/option_opaque_data_tuples_unittest.cc b/src/lib/dhcp/tests/option_opaque_data_tuples_unittest.cc new file mode 100644 index 0000000..6bbd766 --- /dev/null +++ b/src/lib/dhcp/tests/option_opaque_data_tuples_unittest.cc @@ -0,0 +1,253 @@ +// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <exceptions/exceptions.h> +#include <dhcp/option_opaque_data_tuples.h> +#include <util/buffer.h> +#include <gtest/gtest.h> + +using namespace isc; +using namespace isc::dhcp; +using namespace isc::util; + +namespace { + +// This test checks that the DHCPv6 option constructor sets the default +// properties to the expected values. +TEST(OptionOpaqueDataTuples, constructor6) { + OptionOpaqueDataTuples data_tuple(Option::V6, 60); + // Option length is 2 bytes for option code + 2 bytes for option size + EXPECT_EQ(4, data_tuple.len()); + // There should be no tuples. + EXPECT_EQ(0, data_tuple.getTuplesNum()); +} + +// This test verifies that it is possible to append the opaque data tuple +// to the option and then retrieve it. +TEST(OptionOpaqueDataTuples, addTuple) { + OptionOpaqueDataTuples data_tuple(Option::V6, 60); + // Initially there should be no tuples (for DHCPv6). + ASSERT_EQ(0, data_tuple.getTuplesNum()); + // Create a new tuple and add it to the option. + OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES); + tuple = "xyz"; + data_tuple.addTuple(tuple); + // The option should now hold one tuple. + ASSERT_EQ(1, data_tuple.getTuplesNum()); + EXPECT_EQ("xyz", data_tuple.getTuple(0).getText()); + // Add another tuple. + tuple = "abc"; + data_tuple.addTuple(tuple); + // The option should now hold exactly two tuples in the order in which + // they were added. + ASSERT_EQ(2, data_tuple.getTuplesNum()); + EXPECT_EQ("xyz", data_tuple.getTuple(0).getText()); + EXPECT_EQ("abc", data_tuple.getTuple(1).getText()); + + // Check that hasTuple correctly identifies existing tuples. + EXPECT_TRUE(data_tuple.hasTuple("xyz")); + EXPECT_TRUE(data_tuple.hasTuple("abc")); + EXPECT_FALSE(data_tuple.hasTuple("other")); + + // Attempt to add the tuple with 1 byte long length field should fail + // for DHCPv6 option. + OpaqueDataTuple tuple2(OpaqueDataTuple::LENGTH_1_BYTE); + EXPECT_THROW(data_tuple.addTuple(tuple2), isc::BadValue); + + // Similarly, adding a tuple with 2 bytes long length field should + // fail for DHCPv4 option. + OptionOpaqueDataTuples data_tuple2(Option::V4, 65); + OpaqueDataTuple tuple3(OpaqueDataTuple::LENGTH_2_BYTES); + EXPECT_THROW(data_tuple2.addTuple(tuple3), isc::BadValue); +} + +// This test checks that it is possible to replace existing tuple. +TEST(OptionOpaqueDataTuples, setTuple) { + OptionOpaqueDataTuples data_tuple(Option::V6, 60); + // Initially there should be no tuples (for DHCPv6). + ASSERT_EQ(0, data_tuple.getTuplesNum()); + // Add a tuple + OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES); + tuple = "xyz"; + data_tuple.addTuple(tuple); + + // Add another one. + tuple = "abc"; + data_tuple.addTuple(tuple); + ASSERT_EQ(2, data_tuple.getTuplesNum()); + ASSERT_EQ("abc", data_tuple.getTuple(1).getText()); + + // Try to replace them with new tuples. + tuple = "new_xyz"; + ASSERT_NO_THROW(data_tuple.setTuple(0, tuple)); + ASSERT_EQ(2, data_tuple.getTuplesNum()); + EXPECT_EQ("new_xyz", data_tuple.getTuple(0).getText()); + + tuple = "new_abc"; + ASSERT_NO_THROW(data_tuple.setTuple(1, tuple)); + ASSERT_EQ(2, data_tuple.getTuplesNum()); + EXPECT_EQ("new_abc", data_tuple.getTuple(1).getText()); + + // For out of range position, exception should be thrown. + tuple = "foo"; + EXPECT_THROW(data_tuple.setTuple(2, tuple), isc::OutOfRange); +} + +// Check that the returned length of the DHCPv6 option is correct. +TEST(OptionOpaqueDataTuples, len6) { + OptionOpaqueDataTuples data_tuple(Option::V6, 60); + ASSERT_EQ(4, data_tuple.len()); + // Add first tuple. + OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES); + tuple = "xyz"; + ASSERT_NO_THROW(data_tuple.addTuple(tuple)); + // The total length grows by 2 bytes of the length field and 3 bytes + // consumed by 'xyz'. + EXPECT_EQ(9, data_tuple.len()); + // Add another tuple and check that the total size gets increased. + tuple = "abc"; + data_tuple.addTuple(tuple); + EXPECT_EQ(14, data_tuple.len()); +} + +// Check that the DHCPv6 option is rendered to the buffer in wire format. +TEST(OptionOpaqueDataTuples, pack6) { + OptionOpaqueDataTuples data_tuple(Option::V6, 60); + ASSERT_EQ(0, data_tuple.getTuplesNum()); + // Add tuple. + OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES); + tuple = "Hello world"; + data_tuple.addTuple(tuple); + // And add another tuple so as resulting option is a bit more complex. + tuple = "foo"; + data_tuple.addTuple(tuple); + + // Render the data to the buffer. + OutputBuffer buf(10); + ASSERT_NO_THROW(data_tuple.pack(buf)); + ASSERT_EQ(22, buf.getLength()); + + // Prepare reference data. + const uint8_t ref[] = { + 0x00, 0x3C, 0x00, 0x12, // option 60, length 18 + 0x00, 0x0B, // tuple length is 11 + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, // Hello<space> + 0x77, 0x6F, 0x72, 0x6C, 0x64, // world + 0x00, 0x03, // tuple length is 3 + 0x66, 0x6F, 0x6F // foo + }; + // Compare the buffer with reference data. + EXPECT_EQ(0, memcmp(static_cast<const void*>(ref), + static_cast<const void*>(buf.getData()), + buf.getLength())); +} + +// This function checks that the DHCPv6 option with two opaque data tuples +// is parsed correctly. +TEST(OptionOpaqueDataTuples, unpack6) { + // Prepare data to decode. + const uint8_t buf_data[] = { + 0x00, 0x0B, // tuple length is 11 + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, // Hello<space> + 0x77, 0x6F, 0x72, 0x6C, 0x64, // world + 0x00, 0x03, // tuple length is 3 + 0x66, 0x6F, 0x6F // foo + }; + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + + OptionOpaqueDataTuplesPtr data_tuple; + ASSERT_NO_THROW( + data_tuple = OptionOpaqueDataTuplesPtr(new OptionOpaqueDataTuples(Option::V6, + 60, + buf.begin(), + buf.end())); + ); + EXPECT_EQ(D6O_BOOTFILE_PARAM, data_tuple->getType()); + ASSERT_EQ(2, data_tuple->getTuplesNum()); + EXPECT_EQ("Hello world", data_tuple->getTuple(0).getText()); + EXPECT_EQ("foo", data_tuple->getTuple(1).getText()); +} + +// This test checks that the DHCPv6 option with opaque data of size 0 +// is correctly parsed. +TEST(OptionOpaqueDataTuples, unpack6EmptyTuple) { + // Prepare data to decode. + const uint8_t buf_data[] = {0x00, 0x00}; // tuple length is 0 + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + + OptionOpaqueDataTuplesPtr data_tuple; + ASSERT_NO_THROW( + data_tuple = OptionOpaqueDataTuplesPtr(new OptionOpaqueDataTuples(Option::V6, + 60, + buf.begin(), + buf.end())); + ); + EXPECT_EQ(D6O_BOOTFILE_PARAM, data_tuple->getType()); + ASSERT_EQ(1, data_tuple->getTuplesNum()); + EXPECT_TRUE(data_tuple->getTuple(0).getText().empty()); +} + +// This test checks that exception is thrown when parsing truncated DHCPv6 +// bootfile-param option +TEST(OptionOpaqueDataTuples, unpack6Truncated) { + // Prepare data to decode. + const uint8_t buf_data[] = { + 0x00, 0x0B, // tuple length is 11 + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, // Hello<space> + 0x77, 0x6F, 0x72, 0x6C // worl (truncated d!) + }; + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + + EXPECT_THROW(OptionOpaqueDataTuples (Option::V6, 60, buf.begin(), buf.end()), + isc::dhcp::OpaqueDataTupleError); +} + +// This test checks that the DHCPv6 bootfile-param option containing no opaque +// data is parsed correctly. +TEST(OptionOpaqueDataTuples, unpack6NoTuple) { + // Prepare data to decode. + const uint8_t buf_data[] = { + }; + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + + OptionOpaqueDataTuplesPtr data_tuple; + ASSERT_NO_THROW( + data_tuple = OptionOpaqueDataTuplesPtr(new OptionOpaqueDataTuples(Option::V6, + 60, + buf.begin(), + buf.end())); + ); + EXPECT_EQ(D6O_BOOTFILE_PARAM, data_tuple->getType()); + EXPECT_EQ(0, data_tuple->getTuplesNum()); +} + +// Verifies correctness of the text representation of the DHCPv6 option. +TEST(OptionOpaqueDataTuples, toText6) { + OptionOpaqueDataTuples data_tuple(Option::V6, 60); + ASSERT_EQ(0, data_tuple.getTuplesNum()); + // Lets add a tuple + OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES); + tuple = "Hello world"; + data_tuple.addTuple(tuple); + // And add another tuple so as resulting option is a bit more complex. + tuple = "foo"; + data_tuple.addTuple(tuple); + // Check that the text representation of the option is as expected. + EXPECT_EQ("type=60, len=18," + " data-len0=11, data0='Hello world'," + " data-len1=3, data1='foo'", + data_tuple.toText()); + + // Check that indentation works. + EXPECT_EQ(" type=60, len=18," + " data-len0=11, data0='Hello world'," + " data-len1=3, data1='foo'", + data_tuple.toText(2)); +} + +} // end of anonymous namespace |