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);
+// This test verifies constructor from convenient string notation
+// with one ADN-only-mode DNR instance.
+TEST(Option4DnrTest, fromConfigCtorOneAdnOnlyModeInstance) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com.";
- // Check if member variables were correctly set by ctor.
- EXPECT_EQ(Option::V4, option->getUniverse());
- EXPECT_EQ(DHO_V4_DNR, option->getType());
-}
+ OptionBuffer in_buf;
+ in_buf.assign(config.begin(), config.end());
-// 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()));
+ EXPECT_NO_THROW(option.reset(new Option4Dnr(in_buf.begin(), in_buf.end(), true)));
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());
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) {
+// This test verifies constructor from convenient string notation
+// with multiple ADN-only-mode DNR instances.
+TEST(Option4DnrTest, fromConfigCtorMultipleAdnOnlyModeInstances) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com. | "
+ "3, myhost3.example.com.";
+
+ OptionBuffer in_buf;
+ in_buf.assign(config.begin(), config.end());
+
// Create option instance. Check that constructor doesn't throw.
Option4DnrPtr option;
- EXPECT_NO_THROW(option.reset(new Option4Dnr()));
+ EXPECT_NO_THROW(option.reset(new Option4Dnr(in_buf.begin(), in_buf.end(), true)));
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());
option->toText());
}
-// This test verifies constructor of the empty Option4Dnr class together
-// with adding to option's DNR instances:
+// This test verifies constructor from convenient string notation
+// with two DNR instances:
// 1. ADN-only-mode DNR instance
// 2. All fields included (IP addresses and service params also) DNR instance.
-TEST(Option4DnrTest, mixedDnrInstances) {
+TEST(Option4DnrTest, fromConfigCtorMixedDnrInstances) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, "
+ "alpn=h3 port=1234 dohpath=/q{?dns}";
+
+ OptionBuffer in_buf;
+ in_buf.assign(config.begin(), config.end());
+
// Create option instance. Check that constructor doesn't throw.
Option4DnrPtr option;
- EXPECT_NO_THROW(option.reset(new Option4Dnr()));
+ EXPECT_NO_THROW(option.reset(new Option4Dnr(in_buf.begin(), in_buf.end(), true)));
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(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());
+
+ // Reference SvcParams on-wire data buffer.
+ const OptionBuffer svc_params = {
+ 0, 1, // SvcParamKey alpn
+ 0, 3, // SvcParamVal Len
+ 2, 'h', '3', // 2 octets long alpn-id http/3
+ 0, 3, // SvcParamKey port
+ 0, 2, // SvcParamVal Len
+ 0x4, 0xD2, // 1234 in hex
+ 0, 7, // SvcParamKey dohpath
+ 0, 8, // SvcParamVal Len
+ '/', 'q', '{', '?', 'd', 'n', 's', '}' // dohpath value
+ };
+
EXPECT_EQ(svc_params, option->getDnrInstances()[1].getSvcParams());
+ EXPECT_EQ(svc_params.size(), option->getDnrInstances()[1].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)
// + 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());
+ // + 8 (IP addresses) + 25 (svc params)
+ // = 88
+ EXPECT_EQ(88, 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, "
+ EXPECT_EQ("type=162(V4_DNR), len=86, "
"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, "
+ "DNR Instance 2(Instance len=58, 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')",
+ "svc_params='alpn=h3 port=1234 dohpath=/q{?dns}')",
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) {
+TEST(Option4DnrTest, fromConfigCtorPackOneAdnOnlyModeInstance) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com.";
+
+ OptionBuffer in_buf;
+ in_buf.assign(config.begin(), config.end());
+
// Create option instance. Check that constructor doesn't throw.
Option4DnrPtr option;
- EXPECT_NO_THROW(option.reset(new Option4Dnr()));
+ EXPECT_NO_THROW(option.reset(new Option4Dnr(in_buf.begin(), in_buf.end(), true)));
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));
// 1. ADN only mode
// 2. ADN only mode
// 3. ADN only mode
-TEST(Option4DnrTest, packMultipleAdnOnlyModeInstances) {
+TEST(Option4DnrTest, fromConfigCtorPackMultipleAdnOnlyModeInstances) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com. | "
+ "3, myhost3.example.com.";
+
+ OptionBuffer in_buf;
+ in_buf.assign(config.begin(), config.end());
+
// Create option instance. Check that constructor doesn't throw.
Option4DnrPtr option;
- EXPECT_NO_THROW(option.reset(new Option4Dnr()));
+ EXPECT_NO_THROW(option.reset(new Option4Dnr(in_buf.begin(), in_buf.end(), true)));
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));
// 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) {
+TEST(Option4DnrTest, fromConfigCtorPackMixedDnrInstances) {
// Create option instance. Check that constructor doesn't throw.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,doq";
+ OptionBuffer opt_buf;
+ opt_buf.assign(config.begin(), config.end());
Option4DnrPtr option;
- EXPECT_NO_THROW(option.reset(new Option4Dnr()));
+ EXPECT_NO_THROW(option.reset(new Option4Dnr(opt_buf.begin(), opt_buf.end(), true)));
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));
+ isc::util::OutputBuffer out_buf(10);
+ ASSERT_NO_THROW(option->pack(out_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
+ DHO_V4_DNR, // Option code
+ 73, // Option len
+ 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, 45, // 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
+ 0, 1, // SvcParamKey alpn
+ 0, 8, // SvcParamVal Len
+ 3, 'd', 'o', 't', // 3 octets long alpn-id dot
+ 3, 'd', 'o', 'q' // 3 octets long alpn-id doq
+
};
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()));
+ ASSERT_EQ(ref_data_size, out_buf.getLength());
+ EXPECT_EQ(0, memcmp(ref_data, out_buf.getData(), out_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[] = {
+// This test verifies option packing into wire data.
+// Provided data to pack contains 2 DNR instances:
+// 1. ADN only mode
+// 2. Almost all fields included (IP addresses but no service params).
+TEST(Option4DnrTest, fromConfigCtorPackMixedDnrInstancesTwo) {
+ // Create option instance. Check that constructor doesn't throw.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2";
+ OptionBuffer opt_buf;
+ opt_buf.assign(config.begin(), config.end());
+ Option4DnrPtr option;
+ EXPECT_NO_THROW(option.reset(new Option4Dnr(opt_buf.begin(), opt_buf.end(), true)));
+ ASSERT_TRUE(option);
+
+ // Prepare on-wire format of the option.
+ isc::util::OutputBuffer out_buf(10);
+ ASSERT_NO_THROW(option->pack(out_buf));
+
+ // Prepare reference data.
+ const uint8_t ref_data[] = {
+ DHO_V4_DNR, // Option code
+ 61, // Option len
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.
+ 0x03, 0x63, 0x6F, 0x6D, 0x00, // com.
+ 0x00, 33, // 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
};
- OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
+ 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, out_buf.getLength());
+ EXPECT_EQ(0, memcmp(ref_data, out_buf.getData(), out_buf.getLength()));
+}
+
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - DnrInstance config has only Svc Priority.
+TEST(Option4DnrTest, fromConfigCtorNotEnoughFields) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,h3 "
+ "dohpath=/some\\|path{?dns} | " // "pipe char" escape is tested here
+ "3"; // 3rd dnr instance config has only Svc Priority
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ BadValue);
+ ASSERT_FALSE(option);
+}
+
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - DnrInstance config has too many comma separated fields.
+TEST(Option4DnrTest, fromConfigCtorTooManyFields) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,h3 "
+ "dohpath=/some-path{?dns} | "
+ "3, test.com., 10.2.3.4, port=1234, extra"; // too many fields
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ BadValue);
+ ASSERT_FALSE(option);
+}
+
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - DnrInstance config has malformed Svc priority.
+TEST(Option4DnrTest, fromConfigCtorWrongSvcPriority) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,h3 "
+ "dohpath=/some-path{?dns} | "
+ "what?, test.com., 10.2.3.4, port=1234"; // non-parsable Svc Priority
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ BadValue);
+ ASSERT_FALSE(option);
+}
+
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - DnrInstance config has malformed ADN.
+TEST(Option4DnrTest, fromConfigCtorWrongAdn) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,h3 "
+ "dohpath=/some-path{?dns} | "
+ "100, , 10.2.3.4, port=1234"; // wrong ADN - empty
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ InvalidOptionDnrDomainName);
+ ASSERT_FALSE(option);
+}
+
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - DnrInstance config has malformed IP address.
+TEST(Option4DnrTest, fromConfigCtorWrongIpAddr) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,h3 "
+ "dohpath=/some-path{?dns} | "
+ "100, test.net. , what?, port=1234"; // wrong IP address
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ BadValue);
+ ASSERT_FALSE(option);
+}
+
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - DnrInstance config has no IP address.
+TEST(Option4DnrTest, fromConfigCtorNoIpAddr) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,h3 "
+ "dohpath=/some-path{?dns} | "
+ "100, test.net. , , port=1234"; // no IP address
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ BadValue);
+ ASSERT_FALSE(option);
+}
+
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - DnrInstance config has malformed SvcParams.
+TEST(Option4DnrTest, fromConfigCtorWrongSvcParams) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,h3 "
+ "dohpath=/some-path{?dns} | "
+ "100, test.net. , 10.2.3.4, ="; // wrong SvcParams
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ InvalidOptionDnrSvcParams);
+ ASSERT_FALSE(option);
+}
+
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - DnrInstance config has malformed SvcParams - forbidden SvcParam.
+TEST(Option4DnrTest, fromConfigCtorWrongSvcParamsForbiddenSvcParam) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,h3 "
+ "dohpath=/some-path{?dns} | "
+ "100, test.net. , 10.2.3.4, ipv4hint=1"; // forbidden SvcParam
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ InvalidOptionDnrSvcParams);
+ ASSERT_FALSE(option);
+}
+
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - DnrInstance config has malformed SvcParams - unknown SvcParam.
+TEST(Option4DnrTest, fromConfigCtorWrongSvcParamsUnknownSvcParam) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,h3 "
+ "dohpath=/some-path{?dns} | "
+ "100, test.net. , 10.2.3.4, unknown=1"; // unknown SvcParam
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ InvalidOptionDnrSvcParams);
+ ASSERT_FALSE(option);
+}
+
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - DnrInstance config has malformed SvcParams - not supported SvcParam.
+TEST(Option4DnrTest, fromConfigCtorWrongSvcParamsNotSupportedSvcParam) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,h3 "
+ "dohpath=/some-path{?dns} | "
+ "100, test.net. , 10.2.3.4, ech=1"; // ech is not supported in DNR
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ InvalidOptionDnrSvcParams);
+ ASSERT_FALSE(option);
+}
+
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - DnrInstance config has malformed SvcParams - duplicated SvcParam.
+TEST(Option4DnrTest, fromConfigCtorWrongSvcParamsDuplicatedSvcParam) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,h3 "
+ "dohpath=/some-path{?dns} | "
+ "100, test.net. , 10.2.3.4,"
+ " port=1234 port=2345"; // duplicated SvcParam
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ InvalidOptionDnrSvcParams);
+ ASSERT_FALSE(option);
+}
+
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - DnrInstance config has malformed SvcParams - unknown AlpnId.
+TEST(Option4DnrTest, fromConfigCtorWrongSvcParamsUnknownAlpnId) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,h3 "
+ "dohpath=/some-path{?dns} | "
+ "100, test.net. , 10.2.3.4, alpn=dot\\,unknown"; // unknown alpn-id
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ InvalidOptionDnrSvcParams);
+ ASSERT_FALSE(option);
+}
+
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - DnrInstance config has malformed SvcParams - dohpath is missing.
+TEST(Option4DnrTest, fromConfigCtorWrongSvcParamsSkippedDohpath) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,h3 "
+ "dohpath=/some-path{?dns} | "
+ "100, test.net. , 10.2.3.4, alpn=h3"; // dohpath must be there
+ // when any of http alpn-ids
+ // are included
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ InvalidOptionDnrSvcParams);
+ ASSERT_FALSE(option);
+}
+
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - DnrInstance config has malformed SvcParams - port can't be parsed.
+TEST(Option4DnrTest, fromConfigCtorWrongSvcParamsWrongPort) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,h3 "
+ "dohpath=/some-path{?dns} | "
+ "100, test.net. , 10.2.3.4, port=what?"; // port must be uint_16
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ InvalidOptionDnrSvcParams);
+ ASSERT_FALSE(option);
+}
+
+// This test verifies that option constructor throws
+// an exception when config provided via ctor is malformed
+// - DnrInstance config has malformed SvcParams - dns var missing in dohpath.
+TEST(Option4DnrTest, fromConfigCtorWrongSvcParamsMissingVarInDohpath) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, alpn=dot\\,h3 "
+ "dohpath=/some-path{?dns} | "
+ "100, test.net. , 10.2.3.4, alpn=dot\\,h3 "
+ "dohpath=/some-path"; // dns var is missing in the uri of dohpath
+
+ OptionBuffer buf;
+ buf.assign(config.begin(), config.end());
+
+ // Create option instance. Check that constructor throws.
+ Option4DnrPtr option;
+ EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end(), true)),
+ InvalidOptionDnrSvcParams);
+ ASSERT_FALSE(option);
+}
+
+// This test verifies option packing into wire data.
+// Provided data to pack contains 2 DNR instances:
+// 1. ADN only mode
+// 2. All fields included and SvcParams are given in wrong order.
+TEST(Option4DnrTest, fromConfigCtorPackUnorderedSvcParams) {
// Create option instance. Check that constructor doesn't throw.
+ const std::string config = "1, myhost1.example.com. | "
+ "2, myhost2.example.com., 192.168.0.1 192.168.0.2, port=85"
+ " alpn=dot\\,doq"; // SvcParams are NOT in increasing order
+ OptionBuffer opt_buf;
+ opt_buf.assign(config.begin(), config.end());
Option4DnrPtr option;
- EXPECT_NO_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())));
+ EXPECT_NO_THROW(option.reset(new Option4Dnr(opt_buf.begin(), opt_buf.end(), true)));
ASSERT_TRUE(option);
+
+ // Prepare on-wire format of the option.
+ isc::util::OutputBuffer out_buf(10);
+ ASSERT_NO_THROW(option->pack(out_buf));
+
+ // Prepare reference data.
+ const uint8_t ref_data[] = {
+ DHO_V4_DNR, // Option code
+ 79, // Option len
+ 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, 51, // 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
+ 0, 1, // SvcParamKey alpn
+ 0, 8, // SvcParamVal Len
+ 3, 'd', 'o', 't', // 3 octets long alpn-id dot
+ 3, 'd', 'o', 'q', // 3 octets long alpn-id doq
+ 0, 3, // SvcParamKey port is in correct order
+ // after alpn
+ 0, 2, // SvcParamVal Len
+ 0, 85 // port nr
+ };
+
+ 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, out_buf.getLength());
+ EXPECT_EQ(0, memcmp(ref_data, out_buf.getData(), out_buf.getLength()));
}
// This test verifies option constructor from wire data in terms
TEST(Option4DnrTest, unpackOneDnrInstance) {
// Prepare data to decode - 1 DNR instance.
const uint8_t buf_data[] = {
- 0x00, 62, // DNR Instance Data Len
+ 0x00, 45, // 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.
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
+ 0, 1, // SvcParamKey alpn
+ 0, 8, // SvcParamVal Len
+ 3, 'd', 'o', 't', // 3 octets long alpn-id dot
+ 3, 'd', 'o', 'q' // 3 octets long alpn-id doq
};
OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
// Check if data was unpacked correctly from wire data.
const DnrInstance& dnr_i = option->getDnrInstances()[0];
- EXPECT_EQ(62, dnr_i.getDnrInstanceDataLength());
+ EXPECT_EQ(45, 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());
+
+ // Reference SvcParams on-wire data buffer.
+ const OptionBuffer svc_params = {
+ 0, 1, // SvcParamKey alpn
+ 0, 8, // SvcParamVal Len
+ 3, 'd', 'o', 't', // 3 octets long alpn-id dot
+ 3, 'd', 'o', 'q' // 3 octets long alpn-id doq
+ };
+
+ EXPECT_EQ(svc_params, dnr_i.getSvcParams());
+ EXPECT_EQ(svc_params.size(), dnr_i.getSvcParamsLength());
+ EXPECT_EQ(49, option->len());
}
// This test verifies option constructor from wire data in terms
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, 58, // 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.
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
+ 0, 1, // SvcParamKey alpn
+ 0, 3, // SvcParamVal Len
+ 2, 'h', '3', // 2 octets long alpn-id http/3
+ 0, 3, // SvcParamKey port
+ 0, 2, // SvcParamVal Len
+ 0x4, 0xD2, // 1234 in hex
+ 0, 7, // SvcParamKey dohpath
+ 0, 8, // SvcParamVal Len
+ '/', 'q', '{', '?', 'd', 'n', 's', '}' // dohpath value
};
OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
EXPECT_EQ(0, dnr_1.getSvcParamsLength());
const DnrInstance& dnr_2 = option->getDnrInstances()[1];
- EXPECT_EQ(62, dnr_2.getDnrInstanceDataLength());
+ EXPECT_EQ(58, 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());
+ // Reference SvcParams on-wire data buffer.
+ const OptionBuffer svc_params = {
+ 0, 1, // SvcParamKey alpn
+ 0, 3, // SvcParamVal Len
+ 2, 'h', '3', // 2 octets long alpn-id http/3
+ 0, 3, // SvcParamKey port
+ 0, 2, // SvcParamVal Len
+ 0x4, 0xD2, // 1234 in hex
+ 0, 7, // SvcParamKey dohpath
+ 0, 8, // SvcParamVal Len
+ '/', 'q', '{', '?', 'd', 'n', 's', '}' // dohpath value
+ };
+ EXPECT_EQ(svc_params, dnr_2.getSvcParams());
+ EXPECT_EQ(svc_params.size(), dnr_2.getSvcParamsLength());
+
+ EXPECT_EQ(88, option->len());
}
// Test checks that exception is thrown when trying to unpack malformed wire data
}
// Test checks that exception is thrown when trying to unpack malformed wire data
-// - ADN FQDN contains only whitespace - non valid FQDN.
+// - ADN FQDN contains only whitespace - non-valid FQDN.
TEST(Option4DnrTest, unpackInvalidFqdnAdn) {
// Prepare malformed data to decode.
const uint8_t buf_data[] = {
}
// Test checks that exception is thrown when trying to unpack malformed wire data
-// - SvcParams Key contains char that is not allowed.
+// - SvcParams contain unknown SvcParamKey.
TEST(Option4DnrTest, unpackvcParamsInvalidCharKey) {
// Prepare malformed data to decode.
const uint8_t buf_data[] = {
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 +
+ 0, 1, // SvcParamKey alpn
+ 0, 8, // SvcParamVal Len
+ 3, 'd', 'o', 't', // 3 octets long alpn-id dot
+ 3, 'd', 'o', 'q', // 3 octets long alpn-id doq
+ 0, 99, // unknown SvcParamKey
+ 0, 2, // SvcParamVal Len
+ 1, 2 // random data
};
OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
// This test verifies that string representation of the option returned by
// toText method is correctly formatted.
TEST(Option4DnrTest, toText) {
+ // Prepare example config.
+ const std::string config = "1, myhost1.example.com.";
+
+ OptionBuffer in_buf;
+ in_buf.assign(config.begin(), config.end());
+
// Create option instance. Check that constructor doesn't throw.
Option4DnrPtr option;
- EXPECT_NO_THROW(option.reset(new Option4Dnr()));
+ EXPECT_NO_THROW(option.reset(new Option4Dnr(in_buf.begin(), in_buf.end(), true)));
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;