diff options
Diffstat (limited to 'src/lib/dhcp_ddns/tests/ncr_unittests.cc')
-rw-r--r-- | src/lib/dhcp_ddns/tests/ncr_unittests.cc | 742 |
1 files changed, 742 insertions, 0 deletions
diff --git a/src/lib/dhcp_ddns/tests/ncr_unittests.cc b/src/lib/dhcp_ddns/tests/ncr_unittests.cc new file mode 100644 index 0000000..6ac2d09 --- /dev/null +++ b/src/lib/dhcp_ddns/tests/ncr_unittests.cc @@ -0,0 +1,742 @@ +// Copyright (C) 2013-2021 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_ddns/ncr_io.h> +#include <dhcp/duid.h> +#include <dhcp/hwaddr.h> +#include <util/time_utilities.h> + +#include <testutils/gtest_utils.h> +#include <gtest/gtest.h> +#include <algorithm> + +using namespace std; +using namespace isc; +using namespace isc::dhcp_ddns; +using namespace isc::dhcp; + +namespace { + +/// @brief Defines a list of valid JSON NameChangeRequest renditions. +/// They are used as input to test conversion from JSON. +const char *valid_msgs[] = +{ + // Valid Add. + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : true , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"010203040A7F8E3D\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300, " + " \"use-conflict-resolution\": true" + "}", + // Valid Remove. + "{" + " \"change-type\" : 1 , " + " \"forward-change\" : true , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"010203040A7F8E3D\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300, " + " \"use-conflict-resolution\": true" + "}", + // Valid Add with IPv6 address + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : true , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"fe80::2acf:e9ff:fe12:e56f\" , " + " \"dhcid\" : \"010203040A7F8E3D\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300, " + " \"use-conflict-resolution\": true" + "}", + // Missing use-conflict-resolution + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : true , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"010203040A7F8E3D\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300 " + "}" +}; + +/// @brief Defines a list of invalid JSON NameChangeRequest renditions. +/// They are used as input to test conversion from JSON. +const char *invalid_msgs[] = +{ + // Invalid change type. + "{" + " \"change-type\" : 7 , " + " \"forward-change\" : true , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"010203040A7F8E3D\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300, " + " \"use-conflict-resolution\": true" + "}", + // Invalid forward change. + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : \"bogus\" , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"010203040A7F8E3D\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300, " + " \"use-conflict-resolution\": true" + "}", + // Invalid reverse change. + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : true , " + " \"reverse-change\" : 500 , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"010203040A7F8E3D\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300, " + " \"use-conflict-resolution\": true" + "}", + // Forward and reverse change both false. + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : false , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"010203040A7F8E3D\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300, " + " \"use-conflict-resolution\": true" + "}", + // Blank FQDN + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : true , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"010203040A7F8E3D\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300, " + " \"use-conflict-resolution\": true" + "}", + // Malformed FQDN + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : true , " + " \"reverse-change\" : false , " + " \"fqdn\" : \".bad_name\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"010203040A7F8E3D\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300, " + " \"use-conflict-resolution\": true" + "}", + // Bad IP address + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : true , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"xxxxxx\" , " + " \"dhcid\" : \"010203040A7F8E3D\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300 " + " \"use-conflict-resolution\": true" + "}", + // Blank DHCID + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : true , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300, " + " \"use-conflict-resolution\": true" + "}", + // Odd number of digits in DHCID + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : true , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"010203040A7F8E3\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300, " + " \"use-conflict-resolution\": true" + "}", + // Text in DHCID + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : true , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"THIS IS BOGUS!!!\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300, " + " \"use-conflict-resolution\": true" + "}", + // Invalid lease expiration string + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : true , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"010203040A7F8E3D\" , " + " \"lease-expires-on\" : \"Wed Jun 26 13:46:46 EDT 2013\" , " + " \"lease-length\" : 1300, " + " \"use-conflict-resolution\": true" + "}", + // Non-integer for lease length. + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : true , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"010203040A7F8E3D\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : \"BOGUS\", " + " \"use-conflict-resolution\": true" + "}", + // Invalid use-conflict-resolution + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : true , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"010203040A7F8E3D\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300, " + " \"use-conflict-resolution\": 777" + "}" +}; + +/// @brief Tests the NameChangeRequest constructors. +/// This test verifies that: +/// 1. Default constructor works. +/// 2. "Full" constructor, when given valid parameter values, works. +/// 3. "Full" constructor, given a blank FQDN fails +/// 4. "Full" constructor, given an invalid IP Address FQDN fails +/// 5. "Full" constructor, given a blank DHCID fails +/// 6. "Full" constructor, given false for both forward and reverse fails +TEST(NameChangeRequestTest, constructionTests) { + // Verify the default constructor works. + NameChangeRequestPtr ncr; + EXPECT_NO_THROW(ncr.reset(new NameChangeRequest())); + EXPECT_TRUE(ncr); + + // Verify that full constructor works. + uint64_t expiry = isc::util::detail::gettimeWrapper(); + D2Dhcid dhcid("010203040A7F8E3D"); + + EXPECT_NO_THROW(ncr.reset(new NameChangeRequest( + CHG_ADD, true, true, "walah.walah.com", + "192.168.1.101", dhcid, expiry, 1300))); + EXPECT_TRUE(ncr); + ncr.reset(); + + // Verify blank FQDN is detected. + EXPECT_THROW(NameChangeRequest(CHG_ADD, true, true, "", + "192.168.1.101", dhcid, expiry, 1300), NcrMessageError); + + // Verify that an invalid IP address is detected. + EXPECT_THROW(NameChangeRequest(CHG_ADD, true, true, "valid.fqdn", + "xxx.168.1.101", dhcid, expiry, 1300), NcrMessageError); + + // Verify that a blank DHCID is detected. + D2Dhcid blank_dhcid; + EXPECT_THROW(NameChangeRequest(CHG_ADD, true, true, "walah.walah.com", + "192.168.1.101", blank_dhcid, expiry, 1300), NcrMessageError); + + // Verify that one or both of direction flags must be true. + EXPECT_THROW(NameChangeRequest(CHG_ADD, false, false, "valid.fqdn", + "192.168.1.101", dhcid, expiry, 1300), NcrMessageError); + +} + +/// @brief Tests the basic workings of D2Dhcid to and from string conversions. +/// It verifies that: +/// 1. DHCID input strings must contain an even number of characters +/// 2. DHCID input strings must contain only hexadecimal character digits +/// 3. A valid DHCID string converts correctly. +/// 4. Converting a D2Dhcid to a string works correctly. +/// 5. Equality, inequality, and less-than-equal operators work. +TEST(NameChangeRequestTest, dhcidTest) { + D2Dhcid dhcid; + + // Odd number of digits should be rejected. + std::string test_str = "010203040A7F8E3"; + EXPECT_THROW(dhcid.fromStr(test_str), NcrMessageError); + + // Non digit content should be rejected. + test_str = "0102BOGUSA7F8E3D"; + EXPECT_THROW(dhcid.fromStr(test_str), NcrMessageError); + + // Verify that valid input converts into a proper byte array. + test_str = "010203040A7F8E3D"; + ASSERT_NO_THROW(dhcid.fromStr(test_str)); + + // Create a test vector of expected byte contents. + const uint8_t bytes[] = { 0x1, 0x2, 0x3, 0x4, 0xA, 0x7F, 0x8E, 0x3D }; + std::vector<uint8_t> expected_bytes(bytes, bytes + sizeof(bytes)); + + // Fetch the byte vector from the dhcid and verify if equals the expected + // content. + const std::vector<uint8_t>& converted_bytes = dhcid.getBytes(); + EXPECT_EQ(expected_bytes.size(), converted_bytes.size()); + EXPECT_TRUE (std::equal(expected_bytes.begin(), + expected_bytes.begin()+expected_bytes.size(), + converted_bytes.begin())); + + // Convert the new dhcid back to string and verify it matches the original + // DHCID input string. + std::string next_str = dhcid.toStr(); + EXPECT_EQ(test_str, next_str); + + // Test equality, inequality, and less-than-equal operators + test_str="AABBCCDD"; + EXPECT_NO_THROW(dhcid.fromStr(test_str)); + + D2Dhcid other_dhcid; + EXPECT_NO_THROW(other_dhcid.fromStr(test_str)); + + EXPECT_TRUE(dhcid == other_dhcid); + EXPECT_FALSE(dhcid != other_dhcid); + + EXPECT_NO_THROW(other_dhcid.fromStr("BBCCDDEE")); + EXPECT_TRUE(dhcid < other_dhcid); + +} + +/// @brief Test fixture class for testing DHCID creation. +class DhcidTest : public ::testing::Test { +public: + /// @brief Constructor + DhcidTest() { + const uint8_t fqdn_data[] = { + 6, 109, 121, 104, 111, 115, 116, // myhost. + 7, 101, 120, 97, 109, 112, 108, 101, // example. + 3, 99, 111, 109, 0 // com. + }; + wire_fqdn_.assign(fqdn_data, fqdn_data + sizeof(fqdn_data)); + } + + /// @brief Destructor + virtual ~DhcidTest() { + } + + std::vector<uint8_t> wire_fqdn_; +}; + +/// Tests that DHCID is correctly created from a DUID and FQDN. The final format +/// of the DHCID is as follows: +/// <identifier-type> <digest-type-code> <digest> +/// where: +/// - identifier-type (2 octets) is 0x0002. +/// - digest-type-code (1 octet) indicates SHA-256 hashing and is equal 0x1. +/// - digest = SHA-256(<DUID> <FQDN>) +/// Note: FQDN is given in the on-wire canonical format. +TEST_F(DhcidTest, fromDUID) { + D2Dhcid dhcid; + + // Create DUID. + uint8_t duid_data[] = { 0, 1, 2, 3, 4, 5, 6 }; + DUID duid(duid_data, sizeof(duid_data)); + + // Create DHCID. + ASSERT_NO_THROW(dhcid.fromDUID(duid, wire_fqdn_)); + + // The reference DHCID (represented as string of hexadecimal digits) + // has been calculated using one of the online calculators. + std::string dhcid_ref = "0002012191B7B21AF97E0E656DF887C5E2D" + "EF30E7758A207EDF4CCB2DE8CA37066021C"; + + // Make sure that the DHCID is valid. + EXPECT_EQ(dhcid_ref, dhcid.toStr()); +} + +// Test that DHCID is correctly created when the DUID has minimal length (1). +TEST_F(DhcidTest, fromMinDUID) { + D2Dhcid dhcid; + + // Create DUID. + uint8_t duid_data[] = { 1 }; + DUID duid(duid_data, sizeof(duid_data)); + + // Create DHCID. + ASSERT_NO_THROW(dhcid.fromDUID(duid, wire_fqdn_)); + + // The reference DHCID (represented as string of hexadecimal digits) + // has been calculated using one of the online calculators. + std::string dhcid_ref = "000201F89004F73E60CAEDFF514E11CB91D" + "1F45C8F0A55D4BC4C688484A819F8EA4074"; + + // Make sure that the DHCID is valid. + EXPECT_EQ(dhcid_ref, dhcid.toStr()); +} + +// Test that DHCID is correctly created when the DUID has maximal length (128). +TEST_F(DhcidTest, fromMaxDUID) { + D2Dhcid dhcid; + + // Create DUID. + std::vector<uint8_t> duid_data(128, 1); + DUID duid(&duid_data[0], duid_data.size()); + + // Create DHCID. + ASSERT_NO_THROW(dhcid.fromDUID(duid, wire_fqdn_)); + + // The reference DHCID (represented as string of hexadecimal digits) + // has been calculated using one of the online calculators. + std::string dhcid_ref = "00020137D8FBDC0585B44DFA03FAD2E36C6" + "159737D545A12EFB40B0D88D110A5748234"; + + // Make sure that the DHCID is valid. + EXPECT_EQ(dhcid_ref, dhcid.toStr()); +} + +// This test verifies that DHCID is properly computed from a buffer holding +// client identifier data. +TEST_F(DhcidTest, fromClientId) { + D2Dhcid dhcid; + + // Create a buffer holding client id.. + uint8_t clientid_data[] = { 0, 1, 2, 3, 4, 5, 6 }; + std::vector<uint8_t> clientid(clientid_data, + clientid_data + sizeof(clientid_data)); + + // Create DHCID. + ASSERT_NO_THROW(dhcid.fromClientId(clientid, wire_fqdn_)); + + // The reference DHCID (represented as string of hexadecimal digits) + // has been calculated using one of the online calculators. + std::string dhcid_ref = "0001012191B7B21AF97E0E656DF887C5E2D" + "EF30E7758A207EDF4CCB2DE8CA37066021C"; + + // Make sure that the DHCID is valid. + EXPECT_EQ(dhcid_ref, dhcid.toStr()); + + // Make sure that the empty FQDN is not accepted. + std::vector<uint8_t> empty_wire_fqdn; + EXPECT_THROW(dhcid.fromClientId(clientid, empty_wire_fqdn), + isc::dhcp_ddns::DhcidRdataComputeError); + + // Make sure that the empty client identifier is not accepted. + clientid.clear(); + EXPECT_THROW(dhcid.fromClientId(clientid, wire_fqdn_), + isc::dhcp_ddns::DhcidRdataComputeError); + + +} + +// This test verifies that DHCID is properly computed from a buffer holding +// client identifier data that contains a DUID. +TEST_F(DhcidTest, fromClientIdDUID) { + D2Dhcid dhcid; + + // Create a buffer holding client id.. + uint8_t clientid_data[] = { 0xff, 0x5d, 0xe2, 0x6c, 0x15, 0x00, 0x02, + 0x00, 0x00, 0xab, 0x11, 0x9a, 0x57, 0x20, 0x95, 0x71, 0x61, 0xbd, 0xd0 }; + std::vector<uint8_t> clientid(clientid_data, + clientid_data + sizeof(clientid_data)); + + // Create DHCID. + ASSERT_NO_THROW(dhcid.fromClientId(clientid, wire_fqdn_)); + + // The reference DHCID (represented as string of hexadecimal digits) + std::string dhcid_ref = "000201A250D060B9352AE68E5014B78D25" + "1C30EFB0D5F64E48303B2BC56E6938F129E7"; + + // Make sure that the DHCID is valid. + EXPECT_EQ(dhcid_ref, dhcid.toStr()); + + // Make sure that a too long client identifier is not accepted. + clientid.resize(136); + EXPECT_THROW_MSG(dhcid.fromClientId(clientid, wire_fqdn_), + isc::dhcp_ddns::DhcidRdataComputeError, + "unable to compute DHCID from client identifier," + " embedded DUID length of: 136, is too long"); + + // Make sure that a too short client identifier is not accepted. + clientid.resize(5); + EXPECT_THROW_MSG(dhcid.fromClientId(clientid, wire_fqdn_), + isc::dhcp_ddns::DhcidRdataComputeError, + "unable to compute DHCID from client identifier," + " embedded DUID length of: 5, is too short"); + + // Make sure an empty client identifier is not accepted. + clientid.clear(); + EXPECT_THROW_MSG(dhcid.fromClientId(clientid, wire_fqdn_), + isc::dhcp_ddns::DhcidRdataComputeError, + "empty DUID used to create DHCID"); +} + +// This test verifies that DHCID is properly computed from a HW address. +TEST_F(DhcidTest, fromHWAddr) { + D2Dhcid dhcid; + + // Create a buffer holding client id.. + uint8_t hwaddr_data[] = { 0, 1, 2, 3, 4, 5, 6 }; + HWAddrPtr hwaddr(new HWAddr(hwaddr_data, sizeof(hwaddr_data), + HTYPE_ETHER)); + + // Create DHCID. + ASSERT_NO_THROW(dhcid.fromHWAddr(hwaddr, wire_fqdn_)); + + // The reference DHCID (represented as string of hexadecimal digits) + // has been calculated using one of the online calculators. + std::string dhcid_ref = "0000012247F6DC4423C3E8627434A9D686860" + "9D88948F78018B215EDCAA30C0C135035"; + + // Make sure that the DHCID is valid. + EXPECT_EQ(dhcid_ref, dhcid.toStr()); + + // Make sure that the empty FQDN is not accepted. + std::vector<uint8_t> empty_wire_fqdn; + EXPECT_THROW(dhcid.fromHWAddr(hwaddr, empty_wire_fqdn), + isc::dhcp_ddns::DhcidRdataComputeError); + + // Make sure that the NULL HW address is not accepted. + hwaddr.reset(); + EXPECT_THROW(dhcid.fromHWAddr(hwaddr, wire_fqdn_), + isc::dhcp_ddns::DhcidRdataComputeError); +} + +// test operator<< on D2Dhcid +TEST(NameChangeRequestTest, leftShiftOperation) { + const D2Dhcid dhcid("010203040A7F8E3D"); + + ostringstream oss; + oss << dhcid; + EXPECT_EQ(dhcid.toStr(), oss.str()); +} + +/// @brief Verifies the fundamentals of converting from and to JSON. +/// It verifies that: +/// 1. A NameChangeRequest can be created from a valid JSON string. +/// 2. A valid JSON string can be created from a NameChangeRequest +TEST(NameChangeRequestTest, basicJsonTest) { + // Define valid JSON rendition of a request. + std::string msg_str = "{" + "\"change-type\":1," + "\"forward-change\":true," + "\"reverse-change\":false," + "\"fqdn\":\"walah.walah.com.\"," + "\"ip-address\":\"192.168.2.1\"," + "\"dhcid\":\"010203040A7F8E3D\"," + "\"lease-expires-on\":\"20130121132405\"," + "\"lease-length\":1300," + "\"use-conflict-resolution\":true" + "}"; + + // Verify that a NameChangeRequests can be instantiated from the + // a valid JSON rendition. + NameChangeRequestPtr ncr; + ASSERT_NO_THROW_LOG(ncr = NameChangeRequest::fromJSON(msg_str)); + ASSERT_TRUE(ncr); + + // Verify that the JSON string created by the new request equals the + // original input string. + std::string json_str = ncr->toJSON(); + EXPECT_EQ(msg_str, json_str); + + // Verify that the request ID matches the string from the DHCID. + std::string dhcid_str = "010203040A7F8E3D"; + EXPECT_EQ(dhcid_str, ncr->getRequestId()); +} + +/// @brief Tests a variety of invalid JSON message strings. +/// This test iterates over a list of JSON messages, each containing a single +/// content error. The list of messages is defined by the global array, +/// invalid_messages. Currently that list contains the following invalid +/// conditions: +/// 1. Invalid change type +/// 2. Invalid forward change +/// 3. Invalid reverse change +/// 4. Forward and reverse change both false +/// 5. Invalid forward change +/// 6. Blank FQDN +/// 7. Bad IP address +/// 8. Blank DHCID +/// 9. Odd number of digits in DHCID +/// 10. Text in DHCID +/// 11. Invalid lease expiration string +/// 12. Non-integer for lease length. +/// If more permutations arise they can easily be added to the list. +TEST(NameChangeRequestTest, invalidMsgChecks) { + // Iterate over the list of JSON strings, attempting to create a + // NameChangeRequest. The attempt should throw a NcrMessageError. + int num_msgs = sizeof(invalid_msgs)/sizeof(char*); + for (int i = 0; i < num_msgs; i++) { + EXPECT_THROW(NameChangeRequest::fromJSON(invalid_msgs[i]), + NcrMessageError) << "Invalid message not caught idx: " + << i << std::endl << " text:[" << invalid_msgs[i] << "]" + << std::endl; + } +} + +/// @brief Tests a variety of valid JSON message strings. +/// This test iterates over a list of JSON messages, each containing a single +/// valid request rendition. The list of messages is defined by the global +/// array, valid_messages. Currently that list contains the following valid +/// messages: +/// 1. Valid, IPv4 Add +/// 2. Valid, IPv4 Remove +/// 3. Valid, IPv6 Add +/// If more permutations arise they can easily be added to the list. +TEST(NameChangeRequestTest, validMsgChecks) { + // Iterate over the list of JSON strings, attempting to create a + // NameChangeRequest. The attempt should succeed. + int num_msgs = sizeof(valid_msgs)/sizeof(char*); + for (int i = 0; i < num_msgs; i++) { + EXPECT_NO_THROW(NameChangeRequest::fromJSON(valid_msgs[i])) + << "Valid message failed, message idx: " << i + << std::endl << " text:[" << valid_msgs[i] << "]" + << std::endl; + } +} + +/// @brief Tests converting to and from JSON via isc::util buffer classes. +/// This test verifies that: +/// 1. A NameChangeRequest can be rendered in JSON written to an OutputBuffer +/// 2. A InputBuffer containing a valid JSON request rendition can be used +/// to create a NameChangeRequest. +TEST(NameChangeRequestTest, toFromBufferTest) { + // Define a string containing a valid JSON NameChangeRequest rendition. + std::string msg_str = "{" + "\"change-type\":1," + "\"forward-change\":true," + "\"reverse-change\":false," + "\"fqdn\":\"walah.walah.com.\"," + "\"ip-address\":\"192.168.2.1\"," + "\"dhcid\":\"010203040A7F8E3D\"," + "\"lease-expires-on\":\"20130121132405\"," + "\"lease-length\":1300," + "\"use-conflict-resolution\":true" + "}"; + + // Create a request from JSON directly. + NameChangeRequestPtr ncr; + ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(msg_str)); + + // Verify that we output the request as JSON text to a buffer + // without error. + isc::util::OutputBuffer output_buffer(1024); + ASSERT_NO_THROW(ncr->toFormat(FMT_JSON, output_buffer)); + + // Make an InputBuffer from the OutputBuffer. + isc::util::InputBuffer input_buffer(output_buffer.getData(), + output_buffer.getLength()); + + // Verify that we can create a new request from the InputBuffer. + NameChangeRequestPtr ncr2; + ASSERT_NO_THROW(ncr2 = + NameChangeRequest::fromFormat(FMT_JSON, input_buffer)); + + // Convert the new request to JSON directly. + std::string final_str = ncr2->toJSON(); + + // Verify that the final string matches the original. + ASSERT_EQ(final_str, msg_str); +} + +/// @brief Tests ip address modification and validation +TEST(NameChangeRequestTest, ipAddresses) { + NameChangeRequest ncr; + + // Verify that a valid IPv4 address works. + ASSERT_NO_THROW(ncr.setIpAddress("192.168.1.1")); + const asiolink::IOAddress& io_addr4 = ncr.getIpIoAddress(); + EXPECT_EQ(ncr.getIpAddress(), io_addr4.toText()); + EXPECT_TRUE(ncr.isV4()); + EXPECT_FALSE(ncr.isV6()); + + // Verify that a valid IPv6 address works. + ASSERT_NO_THROW(ncr.setIpAddress("2001:1::f3")); + const asiolink::IOAddress& io_addr6 = ncr.getIpIoAddress(); + EXPECT_EQ(ncr.getIpAddress(), io_addr6.toText()); + EXPECT_FALSE(ncr.isV4()); + EXPECT_TRUE(ncr.isV6()); + + // Verify that an invalid address fails. + ASSERT_THROW(ncr.setIpAddress("x001:1::f3"),NcrMessageError); +} + +/// @brief Tests conversion of NameChangeFormat between enum and strings. +TEST(NameChangeFormatTest, formatEnumConversion){ + ASSERT_EQ(stringToNcrFormat("JSON"), dhcp_ddns::FMT_JSON); + ASSERT_EQ(stringToNcrFormat("jSoN"), dhcp_ddns::FMT_JSON); + ASSERT_THROW(stringToNcrFormat("bogus"), isc::BadValue); + + ASSERT_EQ(ncrFormatToString(dhcp_ddns::FMT_JSON), "JSON"); +} + +/// @brief Tests conversion of NameChangeProtocol between enum and strings. +TEST(NameChangeProtocolTest, protocolEnumConversion){ + ASSERT_EQ(stringToNcrProtocol("UDP"), dhcp_ddns::NCR_UDP); + ASSERT_EQ(stringToNcrProtocol("udP"), dhcp_ddns::NCR_UDP); + ASSERT_EQ(stringToNcrProtocol("TCP"), dhcp_ddns::NCR_TCP); + ASSERT_EQ(stringToNcrProtocol("Tcp"), dhcp_ddns::NCR_TCP); + ASSERT_THROW(stringToNcrProtocol("bogus"), isc::BadValue); + + ASSERT_EQ(ncrProtocolToString(dhcp_ddns::NCR_UDP), "UDP"); + ASSERT_EQ(ncrProtocolToString(dhcp_ddns::NCR_TCP), "TCP"); +} + +TEST(NameChangeRequestTest, useConflictResolutionParsing) { + std::string base_json = + "{" + " \"change-type\" : 0 , " + " \"forward-change\" : true , " + " \"reverse-change\" : false , " + " \"fqdn\" : \"walah.walah.com\" , " + " \"ip-address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"010203040A7F8E3D\" , " + " \"lease-expires-on\" : \"20130121132405\" , " + " \"lease-length\" : 1300 "; + + std::string its_true(base_json + ",\"use-conflict-resolution\": true}"); + NameChangeRequestPtr ncr; + ASSERT_NO_THROW_LOG(ncr = NameChangeRequest::fromJSON(its_true)); + ASSERT_TRUE(ncr); + EXPECT_TRUE(ncr->useConflictResolution()); + + std::string its_false(base_json + ",\"use-conflict-resolution\": false}"); + ASSERT_NO_THROW_LOG(ncr = NameChangeRequest::fromJSON(its_false)); + ASSERT_TRUE(ncr); + EXPECT_FALSE(ncr->useConflictResolution()); + + std::string its_missing(base_json + "}"); + ASSERT_NO_THROW_LOG(ncr = NameChangeRequest::fromJSON(its_true)); + ASSERT_TRUE(ncr); + EXPECT_TRUE(ncr->useConflictResolution()); +} + +} // end of anonymous namespace + |