// Copyright (C) 2013-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 #include #include #include #include #include #include #include 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 expected_bytes(bytes, bytes + sizeof(bytes)); // Fetch the byte vector from the dhcid and verify if equals the expected // content. const std::vector& 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() { // 0x000000066d79686f7374076578616d706c6503636f6d00 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 wire_fqdn_; }; /// Tests that DHCID is correctly created from a DUID and FQDN. The final format /// of the DHCID is as follows: /// /// where: /// - identifier-type (2 octets) is 0x0002. /// - digest-type-code (1 octet) indicates SHA-256 hashing and is equal 0x1. /// - digest = SHA-256( ) /// 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. std::vector duid_data(DUID::MIN_DUID_LEN, 1); DUID duid(duid_data.data(), 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 = "000201202F813E7D9C88BADA41250F2A662" "97742BB9B3EB37C0981D4A905745A30BDD3"; // 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 duid_data(DUID::MAX_DUID_LEN, 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 = "0002015B9022851B4015AD78187BB9BDB98" "7708C5EEA74140B28095ED36FE1EAFEE3F6"; // 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 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 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 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 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