diff options
Diffstat (limited to 'src/lib/dhcp/tests/option4_dnr_unittest.cc')
-rw-r--r-- | src/lib/dhcp/tests/option4_dnr_unittest.cc | 793 |
1 files changed, 793 insertions, 0 deletions
diff --git a/src/lib/dhcp/tests/option4_dnr_unittest.cc b/src/lib/dhcp/tests/option4_dnr_unittest.cc new file mode 100644 index 0000000..60f8cf3 --- /dev/null +++ b/src/lib/dhcp/tests/option4_dnr_unittest.cc @@ -0,0 +1,793 @@ +// Copyright (C) 2023 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 <dhcp/option4_dnr.h> + +#include <gtest/gtest.h> + +using namespace isc; +using namespace isc::dhcp; +using namespace isc::asiolink; + +namespace { + +// This test verifies constructor of the empty Option4Dnr class. +TEST(Option4DnrTest, emptyCtor) { + // Create option instance. Check that constructor doesn't throw. + Option4DnrPtr option; + EXPECT_NO_THROW(option.reset(new Option4Dnr())); + ASSERT_TRUE(option); + + // Check if member variables were correctly set by ctor. + EXPECT_EQ(Option::V4, option->getUniverse()); + EXPECT_EQ(DHO_V4_DNR, option->getType()); +} + +// This test verifies constructor of the empty Option4Dnr class together +// with adding ADN-only-mode DNR instance to option's DNR instances. +TEST(Option4DnrTest, oneAdnOnlyModeInstance) { + // Create option instance. Check that constructor doesn't throw. + Option4DnrPtr option; + EXPECT_NO_THROW(option.reset(new Option4Dnr())); + ASSERT_TRUE(option); + + // Prepare example DNR instance to add. + DnrInstance dnr_1 = DnrInstance(Option::V4, 1, "myhost1.example.com."); + + // Add DNR instance. + option->addDnrInstance(dnr_1); + + // Check if member variables were correctly set inside DNR instances. + EXPECT_EQ(1, option->getDnrInstances().size()); + EXPECT_EQ(1, option->getDnrInstances()[0].getServicePriority()); + EXPECT_EQ(21, option->getDnrInstances()[0].getAdnLength()); + EXPECT_EQ("myhost1.example.com.", option->getDnrInstances()[0].getAdnAsText()); + + // This is ADN only mode, so Addr Length and SvcParams Length + // are both expected to be zero. + EXPECT_EQ(0, option->getDnrInstances()[0].getAddrLength()); + EXPECT_EQ(0, option->getDnrInstances()[0].getSvcParamsLength()); + + // BTW let's check if len() works ok. In ADN only mode, DNR Instance Data Len + // is set to ADN Len (21) + 3 = 24. + // expected len: 1x(24 (ADN+ADN Len+Service priority) + 2 (DNR Instance Data Len)) + 2 (headers) + // = 28 + EXPECT_EQ(28, option->len()); + + // BTW let's check if toText() works ok. + // toText() len does not count in headers len. + EXPECT_EQ("type=162(V4_DNR), len=26, " + "DNR Instance 1(Instance len=24, service_priority=1, " + "adn_length=21, adn='myhost1.example.com.')", + option->toText()); +} + +// This test verifies constructor of the empty Option4Dnr class together +// with adding multiple ADN-only-mode DNR instances to option's DNR instances. +TEST(Option4DnrTest, multipleAdnOnlyModeInstances) { + // Create option instance. Check that constructor doesn't throw. + Option4DnrPtr option; + EXPECT_NO_THROW(option.reset(new Option4Dnr())); + ASSERT_TRUE(option); + + // Check if member variables were correctly set by ctor. + EXPECT_EQ(Option::V4, option->getUniverse()); + EXPECT_EQ(DHO_V4_DNR, option->getType()); + + // Prepare example DNR instances to add. + DnrInstance dnr_1 = DnrInstance(Option::V4, 1, "myhost1.example.com."); + DnrInstance dnr_2 = DnrInstance(Option::V4, 2, "myhost2.example.com."); + DnrInstance dnr_3 = DnrInstance(Option::V4, 3, "myhost3.example.com."); + + // Add DNR instances. + option->addDnrInstance(dnr_1); + option->addDnrInstance(dnr_2); + option->addDnrInstance(dnr_3); + + // Check if member variables were correctly set inside DNR instances. + EXPECT_EQ(3, option->getDnrInstances().size()); + EXPECT_EQ(1, option->getDnrInstances()[0].getServicePriority()); + EXPECT_EQ(2, option->getDnrInstances()[1].getServicePriority()); + EXPECT_EQ(3, option->getDnrInstances()[2].getServicePriority()); + EXPECT_EQ(21, option->getDnrInstances()[0].getAdnLength()); + EXPECT_EQ(21, option->getDnrInstances()[1].getAdnLength()); + EXPECT_EQ(21, option->getDnrInstances()[2].getAdnLength()); + EXPECT_EQ("myhost1.example.com.", option->getDnrInstances()[0].getAdnAsText()); + EXPECT_EQ("myhost2.example.com.", option->getDnrInstances()[1].getAdnAsText()); + EXPECT_EQ("myhost3.example.com.", option->getDnrInstances()[2].getAdnAsText()); + + // This is ADN only mode, so Addr Length and SvcParams Length + // are both expected to be zero. + EXPECT_EQ(0, option->getDnrInstances()[0].getAddrLength()); + EXPECT_EQ(0, option->getDnrInstances()[0].getSvcParamsLength()); + EXPECT_EQ(0, option->getDnrInstances()[1].getAddrLength()); + EXPECT_EQ(0, option->getDnrInstances()[1].getSvcParamsLength()); + EXPECT_EQ(0, option->getDnrInstances()[2].getAddrLength()); + EXPECT_EQ(0, option->getDnrInstances()[2].getSvcParamsLength()); + + // BTW let's check if len() works ok. In ADN only mode, DNR Instance Data Len + // is set to ADN Len (21) + 3 = 24. + // expected len: 3x(24 (ADN+ADN Len+Service priority) + 2 (DNR Instance Data Len)) + 2 (headers) + // = 78 + 2 = 80 + EXPECT_EQ(80, option->len()); + + // BTW let's check if toText() works ok. + // toText() len does not count in headers len. + EXPECT_EQ("type=162(V4_DNR), len=78, " + "DNR Instance 1(Instance len=24, service_priority=1, " + "adn_length=21, adn='myhost1.example.com.'), " + "DNR Instance 2(Instance len=24, service_priority=2, " + "adn_length=21, adn='myhost2.example.com.'), " + "DNR Instance 3(Instance len=24, service_priority=3, " + "adn_length=21, adn='myhost3.example.com.')", + option->toText()); +} + +// This test verifies constructor of the empty Option4Dnr class together +// with adding to option's DNR instances: +// 1. ADN-only-mode DNR instance +// 2. All fields included (IP addresses and service params also) DNR instance. +TEST(Option4DnrTest, mixedDnrInstances) { + // Create option instance. Check that constructor doesn't throw. + Option4DnrPtr option; + EXPECT_NO_THROW(option.reset(new Option4Dnr())); + ASSERT_TRUE(option); + + // Prepare example DNR instance to add. + DnrInstance::AddressContainer addresses; + addresses.push_back(IOAddress("192.168.0.1")); + addresses.push_back(IOAddress("192.168.0.2")); + std::string svc_params = "key123=val key234=val2 key345"; + + DnrInstance dnr_1 = DnrInstance(Option::V4, 1, "myhost1.example.com."); + DnrInstance dnr_2 = DnrInstance(Option::V4, 2, "myhost2.example.com.", addresses, svc_params); + + // Add DNR instance. + option->addDnrInstance(dnr_1); + option->addDnrInstance(dnr_2); + + // Check if member variables were correctly set inside DNR instances. + EXPECT_EQ(2, option->getDnrInstances().size()); + EXPECT_EQ(1, option->getDnrInstances()[0].getServicePriority()); + EXPECT_EQ(21, option->getDnrInstances()[0].getAdnLength()); + EXPECT_EQ("myhost1.example.com.", option->getDnrInstances()[0].getAdnAsText()); + EXPECT_EQ(2, option->getDnrInstances()[1].getServicePriority()); + EXPECT_EQ(21, option->getDnrInstances()[1].getAdnLength()); + EXPECT_EQ("myhost2.example.com.", option->getDnrInstances()[1].getAdnAsText()); + + EXPECT_EQ(0, option->getDnrInstances()[0].getAddrLength()); + EXPECT_EQ(0, option->getDnrInstances()[0].getSvcParamsLength()); + EXPECT_EQ(2, option->getDnrInstances()[1].getAddresses().size()); + EXPECT_EQ(8, option->getDnrInstances()[1].getAddrLength()); + EXPECT_EQ(29, option->getDnrInstances()[1].getSvcParamsLength()); + EXPECT_EQ("192.168.0.1", option->getDnrInstances()[1].getAddresses()[0].toText()); + EXPECT_EQ("192.168.0.2", option->getDnrInstances()[1].getAddresses()[1].toText()); + EXPECT_EQ(svc_params, option->getDnrInstances()[1].getSvcParams()); + + // BTW let's check if len() works ok. In ADN only mode, DNR Instance Data Len + // is set to ADN Len (21) + 3 = 24. + // expected len: 1x(24 (ADN+ADN Len+Service priority) + 2 (DNR Instance Data Len)) + 2 (headers) + // + 24 (ADN+ADN Len+Service priority) + 2 (DNR Instance Data Len) + 1 (Addr Len) + // + 8 (IP addresses) + 29 (svc params) + // = 92 + EXPECT_EQ(92, option->len()); + + // BTW let's check if toText() works ok. + // toText() len does not count in headers len. + EXPECT_EQ("type=162(V4_DNR), len=90, " + "DNR Instance 1(Instance len=24, service_priority=1, " + "adn_length=21, adn='myhost1.example.com.'), " + "DNR Instance 2(Instance len=62, service_priority=2, " + "adn_length=21, adn='myhost2.example.com.', " + "addr_length=8, address(es): 192.168.0.1 192.168.0.2, " + "svc_params='key123=val key234=val2 key345')", + option->toText()); +} + +// This test verifies option packing into wire data. +// Provided data to pack contains 1 DNR instance: +// 1. ADN only mode +TEST(Option4DnrTest, packOneAdnOnlyModeInstance) { + // Create option instance. Check that constructor doesn't throw. + Option4DnrPtr option; + EXPECT_NO_THROW(option.reset(new Option4Dnr())); + ASSERT_TRUE(option); + + // Prepare example DNR instance to add. + DnrInstance dnr_1 = DnrInstance(Option::V4, 1, "myhost1.example.com."); + + // Add DNR instance. + option->addDnrInstance(dnr_1); + + // Prepare on-wire format of the option. + isc::util::OutputBuffer buf(10); + ASSERT_NO_THROW(option->pack(buf)); + + // Prepare reference data. + const uint8_t ref_data[] = { + DHO_V4_DNR, // Option code + 26, // Option len=26 dec + 0x00, 24, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00 // com. + }; + + size_t ref_data_size = sizeof(ref_data) / sizeof(ref_data[0]); + + // Check if the buffer has the same length as the reference data, + // so as they can be compared directly. + ASSERT_EQ(ref_data_size, buf.getLength()); + EXPECT_EQ(0, memcmp(ref_data, buf.getData(), buf.getLength())); +} + +// This test verifies option packing into wire data. +// Provided data to pack contains 3 DNR instances: +// 1. ADN only mode +// 2. ADN only mode +// 3. ADN only mode +TEST(Option4DnrTest, packMultipleAdnOnlyModeInstances) { + // Create option instance. Check that constructor doesn't throw. + Option4DnrPtr option; + EXPECT_NO_THROW(option.reset(new Option4Dnr())); + ASSERT_TRUE(option); + + // Check if member variables were correctly set by ctor. + EXPECT_EQ(Option::V4, option->getUniverse()); + EXPECT_EQ(DHO_V4_DNR, option->getType()); + + // Prepare example DNR instances to add. + DnrInstance dnr_1 = DnrInstance(Option::V4, 1, "myhost1.example.com."); + DnrInstance dnr_2 = DnrInstance(Option::V4, 2, "myhost2.example.com."); + DnrInstance dnr_3 = DnrInstance(Option::V4, 3, "myhost3.example.com."); + + // Add DNR instances. + option->addDnrInstance(dnr_1); + option->addDnrInstance(dnr_2); + option->addDnrInstance(dnr_3); + + // Prepare on-wire format of the option. + isc::util::OutputBuffer buf(10); + ASSERT_NO_THROW(option->pack(buf)); + + // Prepare reference data. + const uint8_t ref_data[] = { + DHO_V4_DNR, // Option code + 78, // Option len=78 dec + 0x00, 24, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 0x00, 24, // DNR Instance Data Len + 0x00, 0x02, // Service priority is 2 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '2', // FQDN: myhost2. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 0x00, 24, // DNR Instance Data Len + 0x00, 0x03, // Service priority is 3 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '3', // FQDN: myhost3. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00 // com. + }; + + size_t ref_data_size = sizeof(ref_data) / sizeof(ref_data[0]); + + // Check if the buffer has the same length as the reference data, + // so as they can be compared directly. + ASSERT_EQ(ref_data_size, buf.getLength()); + EXPECT_EQ(0, memcmp(ref_data, buf.getData(), buf.getLength())); +} + +// This test verifies option packing into wire data. +// Provided data to pack contains 2 DNR instances: +// 1. ADN only mode +// 2. All fields included (IP addresses and service params also). +TEST(Option4DnrTest, packMixedDnrInstances) { + // Create option instance. Check that constructor doesn't throw. + Option4DnrPtr option; + EXPECT_NO_THROW(option.reset(new Option4Dnr())); + ASSERT_TRUE(option); + + // Prepare example DNR instance to add. + DnrInstance::AddressContainer addresses; + addresses.push_back(IOAddress("192.168.0.1")); + addresses.push_back(IOAddress("192.168.0.2")); + std::string svc_params = "key123=val key234=val2 key345"; + + DnrInstance dnr_1 = DnrInstance(Option::V4, 1, "myhost1.example.com."); + DnrInstance dnr_2 = DnrInstance(Option::V4, 2, "myhost2.example.com.", addresses, svc_params); + + // Add DNR instance. + option->addDnrInstance(dnr_1); + option->addDnrInstance(dnr_2); + + // Prepare on-wire format of the option. + isc::util::OutputBuffer buf(10); + ASSERT_NO_THROW(option->pack(buf)); + + // Prepare reference data. + const uint8_t ref_data[] = { + DHO_V4_DNR, // Option code + 90, // Option len=90 dec + 0x00, 24, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 0x00, 62, // DNR Instance Data Len + 0x00, 0x02, // Service priority is 2 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '2', // FQDN: myhost2. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 8, // Addr Len + 192, 168, 0, 1, // IP address 1 + 192, 168, 0, 2, // IP address 2 + 'k', 'e', 'y', '1', '2', '3', '=', 'v', // Svc Params + 'a', 'l', ' ', 'k', 'e', 'y', '2', '3', // Svc Params + '4', '=', 'v', 'a', 'l', '2', ' ', 'k', // Svc Params + 'e', 'y', '3', '4', '5' // Svc Params + }; + + size_t ref_data_size = sizeof(ref_data) / sizeof(ref_data[0]); + + // Check if the buffer has the same length as the reference data, + // so as they can be compared directly. + ASSERT_EQ(ref_data_size, buf.getLength()); + EXPECT_EQ(0, memcmp(ref_data, buf.getData(), buf.getLength())); +} + +// This test verifies option constructor from wire data. +TEST(Option4DnrTest, onWireDataCtor) { + // Prepare data to decode - ADN only mode 1 DNR instance. + const uint8_t buf_data[] = { + 0x00, 24, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00 // com. + }; + + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + // Create option instance. Check that constructor doesn't throw. + Option4DnrPtr option; + EXPECT_NO_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end()))); + ASSERT_TRUE(option); +} + +// This test verifies option constructor from wire data in terms +// of proper data unpacking. +// Provided wire data contains 1 DNR instance: +// 1. ADN only mode +TEST(Option4DnrTest, unpackOneAdnOnly) { + // Prepare data to decode - ADN only mode 1 DNR instance. + const uint8_t buf_data[] = { + 0x00, 24, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00 // com. + }; + + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + // Create option instance. Check that constructor doesn't throw. + Option4DnrPtr option; + EXPECT_NO_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end()))); + ASSERT_TRUE(option); + + // Check if member variables were correctly set by ctor. + EXPECT_EQ(Option::V4, option->getUniverse()); + EXPECT_EQ(DHO_V4_DNR, option->getType()); + + // Check if data was unpacked correctly from wire data. + EXPECT_EQ(24, option->getDnrInstances()[0].getDnrInstanceDataLength()); + EXPECT_EQ(1, option->getDnrInstances()[0].getServicePriority()); + EXPECT_EQ(21, option->getDnrInstances()[0].getAdnLength()); + EXPECT_EQ("myhost1.example.com.", option->getDnrInstances()[0].getAdnAsText()); + + // This is ADN only mode, so Addr Length and SvcParams Length + // are both expected to be zero. + EXPECT_EQ(0, option->getDnrInstances()[0].getAddrLength()); + EXPECT_EQ(0, option->getDnrInstances()[0].getSvcParamsLength()); + + // BTW let's check if len() works ok. In ADN only mode, DNR Instance Data Len + // is set to ADN Len (21) + 3 = 24. + // expected len: 1x(24 (ADN+ADN Len+Service priority) + 2 (DNR Instance Data Len)) + 2 (headers) + // = 28 + EXPECT_EQ(28, option->len()); + + // BTW let's check if toText() works ok. + // toText() len does not count in headers len. + EXPECT_EQ("type=162(V4_DNR), len=26, " + "DNR Instance 1(Instance len=24, service_priority=1, " + "adn_length=21, adn='myhost1.example.com.')", + option->toText()); +} + +// This test verifies option constructor from wire data in terms +// of proper data unpacking. +// Provided wire data contains 1 DNR instance: +// 1. All fields included (IP addresses and service params also). +TEST(Option4DnrTest, unpackOneDnrInstance) { + // Prepare data to decode - 1 DNR instance. + const uint8_t buf_data[] = { + 0x00, 62, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 8, // Addr Len + 192, 168, 0, 1, // IP address 1 + 192, 168, 0, 2, // IP address 2 + 'k', 'e', 'y', '1', '2', '3', '=', 'v', // Svc Params + 'a', 'l', ' ', 'k', 'e', 'y', '2', '3', // Svc Params + '4', '=', 'v', 'a', 'l', '2', ' ', 'k', // Svc Params + 'e', 'y', '3', '4', '5' // Svc Params + }; + + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + // Create option instance. Check that constructor doesn't throw. + Option4DnrPtr option; + EXPECT_NO_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end()))); + ASSERT_TRUE(option); + + // Check if member variables were correctly set by ctor. + EXPECT_EQ(Option::V4, option->getUniverse()); + EXPECT_EQ(DHO_V4_DNR, option->getType()); + + // Check if data was unpacked correctly from wire data. + const DnrInstance& dnr_i = option->getDnrInstances()[0]; + EXPECT_EQ(62, dnr_i.getDnrInstanceDataLength()); + EXPECT_EQ(1, dnr_i.getServicePriority()); + EXPECT_EQ(21, dnr_i.getAdnLength()); + EXPECT_EQ("myhost1.example.com.", dnr_i.getAdnAsText()); + EXPECT_EQ(8, dnr_i.getAddrLength()); + EXPECT_EQ(29, dnr_i.getSvcParamsLength()); + EXPECT_EQ(2, dnr_i.getAddresses().size()); + EXPECT_EQ("192.168.0.1", dnr_i.getAddresses()[0].toText()); + EXPECT_EQ("192.168.0.2", dnr_i.getAddresses()[1].toText()); + EXPECT_EQ("key123=val key234=val2 key345", dnr_i.getSvcParams()); + EXPECT_EQ(66, option->len()); +} + +// This test verifies option constructor from wire data in terms +// of proper data unpacking. +// Provided wire data contains 2 DNR instances: +// 1. ADN only mode +// 2. All fields included (IP addresses and service params also). +TEST(Option4DnrTest, unpackMixedDnrInstances) { + // Prepare data to decode - 2 DNR instances. + const uint8_t buf_data[] = { + 0x00, 24, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 0x00, 62, // DNR Instance Data Len + 0x00, 0x02, // Service priority is 2 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '2', // FQDN: myhost2. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 8, // Addr Len + 192, 168, 0, 1, // IP address 1 + 192, 168, 0, 2, // IP address 2 + 'k', 'e', 'y', '1', '2', '3', '=', 'v', // Svc Params + 'a', 'l', ' ', 'k', 'e', 'y', '2', '3', // Svc Params + '4', '=', 'v', 'a', 'l', '2', ' ', 'k', // Svc Params + 'e', 'y', '3', '4', '5' // Svc Params + }; + + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + // Create option instance. Check that constructor doesn't throw. + Option4DnrPtr option; + EXPECT_NO_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end()))); + ASSERT_TRUE(option); + + // Check if member variables were correctly set by ctor. + EXPECT_EQ(Option::V4, option->getUniverse()); + EXPECT_EQ(DHO_V4_DNR, option->getType()); + + // Check if data was unpacked correctly from wire data. + const DnrInstance& dnr_1 = option->getDnrInstances()[0]; + EXPECT_EQ(24, dnr_1.getDnrInstanceDataLength()); + EXPECT_EQ(1, dnr_1.getServicePriority()); + EXPECT_EQ(21, dnr_1.getAdnLength()); + EXPECT_EQ("myhost1.example.com.", dnr_1.getAdnAsText()); + EXPECT_EQ(0, dnr_1.getAddrLength()); + EXPECT_EQ(0, dnr_1.getSvcParamsLength()); + + const DnrInstance& dnr_2 = option->getDnrInstances()[1]; + EXPECT_EQ(62, dnr_2.getDnrInstanceDataLength()); + EXPECT_EQ(2, dnr_2.getServicePriority()); + EXPECT_EQ(21, dnr_2.getAdnLength()); + EXPECT_EQ("myhost2.example.com.", dnr_2.getAdnAsText()); + EXPECT_EQ(8, dnr_2.getAddrLength()); + EXPECT_EQ(29, dnr_2.getSvcParamsLength()); + EXPECT_EQ(2, dnr_2.getAddresses().size()); + EXPECT_EQ("192.168.0.1", dnr_2.getAddresses()[0].toText()); + EXPECT_EQ("192.168.0.2", dnr_2.getAddresses()[1].toText()); + EXPECT_EQ("key123=val key234=val2 key345", dnr_2.getSvcParams()); + + EXPECT_EQ(92, option->len()); +} + +// Test checks that exception is thrown when trying to unpack malformed wire data +// - mandatory fields are truncated - Service Priority and ADN Len truncated. +TEST(Option4DnrTest, unpackTruncatedDnrInstanceDataLen) { + // Prepare malformed data to decode. + const uint8_t buf_data[] = { + 0x00, 24, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 0x00, 62 // DNR Instance Data Len truncated + }; + + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + + // Create option instance. Check that constructor throws an exception while doing unpack. + Option4DnrPtr option; + EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), OutOfRange); + ASSERT_FALSE(option); +} + +// Test checks that exception is thrown when trying to unpack malformed wire data +// - DNR instance data truncated when compared to DNR Instance Data Len field. +TEST(Option4DnrTest, unpackTruncatedDnrInstanceData) { + // Prepare malformed data to decode. + const uint8_t buf_data[] = { + 0x00, 24, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 0x00, 62, // DNR Instance Data Len + 0x00, 0x02, // Service priority is 2 dec + 21 // ADN Length is 21 dec + // the rest of DNR instance data is truncated + }; + + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + + // Create option instance. Check that constructor throws an exception while doing unpack. + Option4DnrPtr option; + EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), OutOfRange); + ASSERT_FALSE(option); +} + +// Test checks that exception is thrown when trying to unpack malformed wire data +// - ADN field data truncated. +TEST(Option4DnrTest, unpackTruncatedAdn) { + // Prepare malformed data to decode. + const uint8_t buf_data[] = { + 0x00, 24, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 0x00, 3, // DNR Instance Data Len + 0x00, 0x02, // Service priority is 2 dec + 21 // ADN Length is 21 dec + // ADN data is missing. + }; + + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + + // Create option instance. Check that constructor throws an exception while doing unpack. + Option4DnrPtr option; + EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), BadValue); + ASSERT_FALSE(option); +} + +// Test checks that exception is thrown when trying to unpack malformed wire data +// - ADN FQDN contains only whitespace - non valid FQDN. +TEST(Option4DnrTest, unpackInvalidFqdnAdn) { + // Prepare malformed data to decode. + const uint8_t buf_data[] = { + 0x00, 24, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 0x00, 4, // DNR Instance Data Len + 0x00, 0x02, // Service priority is 2 dec + 1, // ADN Length is 1 dec + ' ' // ADN contains only whitespace + }; + + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + + // Create option instance. Check that constructor throws an exception while doing unpack. + Option4DnrPtr option; + EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), InvalidOptionDnrDomainName); + ASSERT_FALSE(option); +} + +// Test checks that exception is thrown when trying to unpack malformed wire data +// - ADN Length is 0 and no ADN FQDN at all. +TEST(Option4DnrTest, unpackNoFqdnAdn) { + // Prepare malformed data to decode. + const uint8_t buf_data[] = { + 0x00, 24, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 0x00, 3, // DNR Instance Data Len + 0x00, 0x02, // Service priority is 2 dec + 0 // ADN Length is 0 dec + }; + + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + + // Create option instance. Check that constructor throws an exception while doing unpack. + Option4DnrPtr option; + EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), InvalidOptionDnrDomainName); + ASSERT_FALSE(option); +} + +// Test checks that exception is thrown when trying to unpack malformed wire data +// - IPv4 address(es) field data truncated. +TEST(Option4DnrTest, unpackTruncatedIpAddress) { + // Prepare malformed data to decode. + const uint8_t buf_data[] = { + 0x00, 24, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 0x00, 25, // DNR Instance Data Len + 0x00, 0x02, // Service priority is 2 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '2', // FQDN: myhost2. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 8 // Addr Len + // the rest of DNR instance data is truncated. + }; + + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + + // Create option instance. Check that constructor throws an exception while doing unpack. + Option4DnrPtr option; + EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), BadValue); + ASSERT_FALSE(option); +} + +// Test checks that exception is thrown when trying to unpack malformed wire data +// - Addr length is 0 and no IPv4 addresses at all. +TEST(Option4DnrTest, unpackNoIpAddress) { + // Prepare malformed data to decode. + const uint8_t buf_data[] = { + 0x00, 24, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 0x00, 25, // DNR Instance Data Len + 0x00, 0x02, // Service priority is 2 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '2', // FQDN: myhost2. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 0 // Addr Len = 0 + }; + + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + + // Create option instance. Check that constructor throws an exception while doing unpack. + Option4DnrPtr option; + EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), OutOfRange); + ASSERT_FALSE(option); +} + +// Test checks that exception is thrown when trying to unpack malformed wire data +// - Addr length is not a multiple of 4. +TEST(Option4DnrTest, unpackIpAddressNon4Modulo) { + // Prepare malformed data to decode. + const uint8_t buf_data[] = { + 0x00, 24, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 0x00, 32, // DNR Instance Data Len + 0x00, 0x02, // Service priority is 2 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '2', // FQDN: myhost2. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 7, // Addr Len + 192, 168, 0, 1, // IP address 1 + 192, 168, 0 // IP address 2 truncated + }; + + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + + // Create option instance. Check that constructor throws an exception while doing unpack. + Option4DnrPtr option; + EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), OutOfRange); + ASSERT_FALSE(option); +} + +// Test checks that exception is thrown when trying to unpack malformed wire data +// - SvcParams Key contains char that is not allowed. +TEST(Option4DnrTest, unpackvcParamsInvalidCharKey) { + // Prepare malformed data to decode. + const uint8_t buf_data[] = { + 0x00, 24, // DNR Instance Data Len + 0x00, 0x01, // Service priority is 1 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 0x00, 39, // DNR Instance Data Len + 0x00, 0x02, // Service priority is 2 dec + 21, // ADN Length is 21 dec + 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '2', // FQDN: myhost2. + 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example. + 0x03, 0x63, 0x6F, 0x6D, 0x00, // com. + 8, // Addr Len + 192, 168, 0, 1, // IP address 1 + 192, 168, 0, 2, // IP address 2 truncated + 'k', 'e', 'y', '+', '2', '3' // Svc Params key has forbidden char + + }; + + OptionBuffer buf(buf_data, buf_data + sizeof(buf_data)); + + // Create option instance. Check that constructor throws an exception while doing unpack. + Option4DnrPtr option; + EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), InvalidOptionDnrSvcParams); + ASSERT_FALSE(option); +} + +// This test verifies that string representation of the option returned by +// toText method is correctly formatted. +TEST(Option4DnrTest, toText) { + // Create option instance. Check that constructor doesn't throw. + Option4DnrPtr option; + EXPECT_NO_THROW(option.reset(new Option4Dnr())); + ASSERT_TRUE(option); + + // Prepare example DNR instance to add. + DnrInstance dnr_1 = DnrInstance(Option::V4, 1, "myhost1.example.com."); + + // Add DNR instance. + option->addDnrInstance(dnr_1); + + // Let's check if toText() works ok. + // toText() len does not count in headers len. + const int indent = 4; + std::string expected = " type=162(V4_DNR), len=26, " // the indentation of 4 spaces + "DNR Instance 1(Instance len=24, service_priority=1, " + "adn_length=21, adn='myhost1.example.com.')"; + EXPECT_EQ(expected, option->toText(indent)); +} + +} // namespace
\ No newline at end of file |