From: Marcin Siodelski Date: Thu, 30 Jun 2016 13:02:25 +0000 (+0200) Subject: [4497] Documented tests for options copying. X-Git-Tag: trac4551_base~23^2~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=21053d3a600dd7c221aed514d97bdd94b2e982a3;p=thirdparty%2Fkea.git [4497] Documented tests for options copying. Also, extended unit test for OptionCustom. --- diff --git a/src/lib/dhcp/tests/option_copy_unittest.cc b/src/lib/dhcp/tests/option_copy_unittest.cc index 10429c98b2..d2108729b3 100644 --- a/src/lib/dhcp/tests/option_copy_unittest.cc +++ b/src/lib/dhcp/tests/option_copy_unittest.cc @@ -39,24 +39,63 @@ using namespace isc::util; namespace { +/// @brief Type of the "copy" operation to be performed in a test. +/// +/// Possible operations are: +/// - copy construction, +/// - cloning with Option::clone, +/// - assignment. enum OpType { COPY, CLONE, ASSIGN }; +/// @brief Generic test for deep copy of an option. +/// +/// This test can use one of the three supported operations to deep copy +/// an option: copy construction, cloning or assignment. +/// +/// After copying the option the following parameters checked if they +/// have been copied (copied by the Option class): +/// - universe, +/// - option type, +/// - encapsulated space, +/// - data. +/// +/// This test also checks that the sub options have been copied by checking +/// that: +/// - options' types match, +/// - binary representations are equal, +/// - pointers to the options are unequal (to make sure that the option has +/// been copied, rather than the pointer). +/// +/// @param op_type Copy operation to be performed. +/// @param option Source option. +/// @param option_copy Destination option. Note that this option may be +/// initially set to a non-null value. For the "copy" and "clone" operations +/// the pointer will be reset, so there is no sense to initialize this +/// object to a non-null value. However, for the assignment testing it is +/// recommended to initialize the option_copy to point to an option having +/// different parameters to verify that all parameters have been overriden +/// by the assignment operation. template void testCopyAssign(const OpType& op_type, boost::shared_ptr& option, boost::shared_ptr& option_copy) { + // Set the encapsulated to 'foo' because tests usually don't set that + // value. option->setEncapsulatedSpace("foo"); + // Create two sub options of different types to later check that they + // are copied. OptionUint16Ptr sub1 = OptionUint16Ptr(new OptionUint16(Option::V4, 10, 234)); Option4AddrLstPtr sub2 = Option4AddrLstPtr(new Option4AddrLst(11, IOAddress("192.0.2.3"))); option->addOption(sub1); option->addOption(sub2); + // Copy option by copy construction, cloning or assignment. switch (op_type) { case COPY: option_copy.reset(new OptionType(*option)); @@ -74,6 +113,7 @@ void testCopyAssign(const OpType& op_type, return; } + // Verify that basic parameters have been copied. EXPECT_EQ(option->getUniverse(), option_copy->getUniverse()); EXPECT_EQ(option->getType(), option_copy->getType()); EXPECT_EQ(option->len(), option_copy->len()); @@ -81,20 +121,27 @@ void testCopyAssign(const OpType& op_type, EXPECT_TRUE(std::equal(option->getData().begin(), option->getData().end(), option_copy->getData().begin())); + // Retrieve sub options so as they can be compared. const OptionCollection& option_subs = option->getOptions(); const OptionCollection& option_copy_subs = option_copy->getOptions(); - ASSERT_EQ(option_subs.size(), option_copy_subs.size()); + + // Iterate over source options. OptionCollection::const_iterator it_copy = option_copy_subs.begin(); for (OptionCollection::const_iterator it = option_subs.begin(); it != option_subs.end(); ++it, ++it_copy) { + // The option codes should be equal in both containers. EXPECT_EQ(it->first, it_copy->first); + // Pointers must be unequal because the expectation is that options + // are copied, rather than pointers. EXPECT_NE(it->second, it_copy->second); Option* opt_ptr = it->second.get(); Option* opt_copy_ptr = it_copy->second.get(); + // The C++ types must match. EXPECT_TRUE(typeid(*opt_ptr) == typeid(*opt_copy_ptr)); } + // Final check is to compare their binary representations. std::vector buf = option->toBinary(true); std::vector buf_copy = option_copy->toBinary(true); @@ -102,6 +149,11 @@ void testCopyAssign(const OpType& op_type, EXPECT_TRUE(std::equal(buf_copy.begin(), buf_copy.end(), buf.begin())); } +// **************************** Option *************************** + +/// @brief Test deep copy of option encapsualated by Option type. +/// +/// @param op_type Copy operation type. void testOption(const OpType& op_type) { OptionBuffer buf(10, 1); OptionPtr option(new Option(Option::V4, 1, buf)); @@ -109,16 +161,22 @@ void testOption(const OpType& op_type) { ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + // Save binary representation of the original option. We will + // be later comparing it with a copied option to make sure that + // modification of the original option doesn't affect the copy. std::vector binary_copy = option_copy->toBinary(true); + // Modify the original option. OptionBuffer buf_modified(10, 2); option->setData(buf_modified.begin(), buf_modified.end()); - std::vector binary_modified = option->toBinary(true); + // Retrieve the binary representation of the copy to verify that + // it hasn't been modified. + std::vector binary_copy_after = option_copy->toBinary(true); - ASSERT_EQ(binary_modified.size(), binary_copy.size()); - EXPECT_FALSE(std::equal(binary_copy.begin(), binary_copy.end(), - binary_modified.begin())); + ASSERT_EQ(binary_copy.size(), binary_copy_after.size()); + EXPECT_TRUE(std::equal(binary_copy_after.begin(), binary_copy_after.end(), + binary_copy.begin())); } TEST(OptionCopyTest, optionConstructor) { @@ -133,18 +191,21 @@ TEST(OptionCopyTest, optionAssignment) { testOption(ASSIGN); } +// **************************** OptionInt *************************** +/// @brief Test deep copy of option encapsualated by OptionInt type. +/// +/// @param op_type Copy operation type. void testOptionInt(const OpType& op_type) { OptionUint16Ptr option(new OptionUint16(Option::V4, 1, 12345)); OptionUint16Ptr option_copy(new OptionUint16(Option::V6, 10, 11111)); ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); - ASSERT_EQ(12345, option->getValue()); - ASSERT_EQ(12345, option_copy->getValue()); - + // Modify value in the original option. option->setValue(9); - ASSERT_EQ(9, option->getValue()); + + // The value in the copy should not be affected. EXPECT_EQ(12345, option_copy->getValue()); } @@ -160,6 +221,11 @@ TEST(OptionCopyTest, optionIntAssignment) { testOptionInt(ASSIGN); } +// ************************* OptionIntArray *************************** + +/// @brief Test deep copy of option encapsualated by OptionIntArray type. +/// +/// @param op_type Copy operation type. void testOptionIntArray(const OpType& op_type) { OptionUint32ArrayPtr option(new OptionUint32Array(Option::V4, 1));; option->addValue(2345); @@ -170,8 +236,10 @@ void testOptionIntArray(const OpType& op_type) { ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + // Modify the values in the original option. option->setValues(std::vector(2, 7)); + // The values in the copy should not be affected. std::vector values_copy = option_copy->getValues(); ASSERT_EQ(2, values_copy.size()); EXPECT_EQ(2345, values_copy[0]); @@ -190,6 +258,18 @@ TEST(OptionCopyTest, optionIntArrayAssignment) { testOptionIntArray(ASSIGN); } +// ************************* Option4AddrLst *************************** + +/// @brief Test deep copy of option encapsualated by Option4AddrLst or +/// Option6AddrLst type. +/// +/// @param op_type Copy operation type. +/// @param option_address Address carried in the source option. +/// @param option_copy_address Address carried in the destination option. +/// @param option_modified_address Address to which the original address +/// is modified to check that this modification doesn't affect option +/// copy. +/// @tparam OptionType Option4AddrLst or Option6AddrLst. template void testOptionAddrLst(const OpType& op_type, const IOAddress& option_address, @@ -201,12 +281,18 @@ void testOptionAddrLst(const OpType& op_type, ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + // Modify the address in the original option. option->setAddress(option_modified_address); + + // The address in the copy should not be affected. typename OptionType::AddressContainer addrs_copy = option_copy->getAddresses(); ASSERT_EQ(1, addrs_copy.size()); EXPECT_EQ(option_address.toText(), addrs_copy[0].toText()); } +/// @brief Test deep copy of option encapsualated by Option4AddrLst type. +/// +/// @param op_type Copy operation type. void testOption4AddrLst(const OpType& op_type) { testOptionAddrLst(op_type, IOAddress("127.0.0.1"), @@ -214,13 +300,6 @@ void testOption4AddrLst(const OpType& op_type) { IOAddress("127.0.0.1")); } -void testOption6AddrLst(const OpType& op_type) { - testOptionAddrLst(op_type, - IOAddress("2001:db8:1::2"), - IOAddress("3001::cafe"), - IOAddress("3000:1::1")); -} - TEST(OptionCopyTest, option4AddrLstConstructor) { testOption4AddrLst(COPY); } @@ -233,6 +312,18 @@ TEST(OptionCopyTest, option4AddrLstAssignment) { testOption4AddrLst(ASSIGN); } +// ************************* Option6AddrLst *************************** + +/// @brief Test deep copy of option encapsualated by Option6AddrLst type. +/// +/// @param op_type Copy operation type. +void testOption6AddrLst(const OpType& op_type) { + testOptionAddrLst(op_type, + IOAddress("2001:db8:1::2"), + IOAddress("3001::cafe"), + IOAddress("3000:1::1")); +} + TEST(OptionCopyTest, option6AddrLstConstructor) { testOption6AddrLst(COPY); } @@ -245,6 +336,11 @@ TEST(OptionCopyTest, option6AddrLstAssignment) { testOption6AddrLst(ASSIGN); } +// *************************** Option6IA *************************** + +/// @brief Test deep copy of option encapsualated by Option6IA type. +/// +/// @param op_type Copy operation type. void testOption6IA(const OpType& op_type) { Option6IAPtr option(new Option6IA(D6O_IA_NA, 1234)); option->setT1(1000); @@ -253,10 +349,12 @@ void testOption6IA(const OpType& op_type) { ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + // Modify the values in the original option. option->setT1(3000); option->setT2(4000); option->setIAID(5678); + // The values in the copy should not be affected. EXPECT_EQ(1000, option_copy->getT1()); EXPECT_EQ(2000, option_copy->getT2()); EXPECT_EQ(1234, option_copy->getIAID()); @@ -274,6 +372,11 @@ TEST(OptionCopyTest, option6IAAssignment) { testOption6IA(ASSIGN); } +// *************************** Option6IAAddr *************************** + +/// @brief Test deep copy of option encapsualated by Option6IAAddr type. +/// +/// @param op_type Copy operation type. void testOption6IAAddr(const OpType& op_type) { Option6IAAddrPtr option(new Option6IAAddr(D6O_IAADDR, IOAddress("2001:db8:1::1"), @@ -284,10 +387,12 @@ void testOption6IAAddr(const OpType& op_type) { ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + // Modify the values in the original option. option->setAddress(IOAddress("2001:db8:1::3")); option->setPreferred(1000); option->setValid(2000); + // The values in the copy should not be affected. EXPECT_EQ("2001:db8:1::1", option_copy->getAddress().toText()); EXPECT_EQ(60, option_copy->getPreferred()); EXPECT_EQ(90, option_copy->getValid()); @@ -305,6 +410,11 @@ TEST(OptionCopyTest, option6IAAddrAssignment) { testOption6IAAddr(ASSIGN); } +// *************************** Option6IAPrefix *************************** + +/// @brief Test deep copy of option encapsualated by Option6IAPrefix type. +/// +/// @param op_type Copy operation type. void testOption6IAPrefix(const OpType& op_type) { Option6IAPrefixPtr option(new Option6IAPrefix(D6O_IAPREFIX, IOAddress("3000::"), @@ -315,10 +425,12 @@ void testOption6IAPrefix(const OpType& op_type) { ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + // Modify the values in the original option. option->setPrefix(IOAddress("3002::"), 32); option->setPreferred(1000); option->setValid(2000); + // The values in the copy should not be affected. EXPECT_EQ("3000::", option_copy->getAddress().toText()); EXPECT_EQ(64, option_copy->getLength()); EXPECT_EQ(60, option_copy->getPreferred()); @@ -337,6 +449,11 @@ TEST(OptionCopyTest, option6IAPrefixAssignment) { testOption6IAPrefix(ASSIGN); } +// *************************** Option6StatusCode *************************** + +/// @brief Test deep copy of option encapsualated by Option6StatusCode type. +/// +/// @param op_type Copy operation type. void testOption6StatusCode(const OpType& op_type) { Option6StatusCodePtr option(new Option6StatusCode(STATUS_NoBinding, "no binding")); @@ -345,9 +462,11 @@ void testOption6StatusCode(const OpType& op_type) { ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + // Modify the values in the original option. option->setStatusCode(STATUS_NoAddrsAvail); option->setStatusMessage("foo"); + // The values in the copy should not be affected. EXPECT_EQ(STATUS_NoBinding, option_copy->getStatusCode()); EXPECT_EQ("no binding", option_copy->getStatusMessage()); } @@ -364,6 +483,11 @@ TEST(OptionCopyTest, option6StatusCodeAssignment) { testOption6StatusCode(ASSIGN); } +// *************************** OptionString *************************** + +/// @brief Test deep copy of option encapsualated by OptionString type. +/// +/// @param op_type Copy operation type. void testOptionString(const OpType& op_type) { OptionStringPtr option(new OptionString(Option::V4, 1, "option value")); OptionStringPtr option_copy(new OptionString(Option::V6, 10, @@ -371,7 +495,10 @@ void testOptionString(const OpType& op_type) { ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + // Modify the string in the original option. option->setValue("foo"); + + // The string in the copy should not be affected. EXPECT_EQ("option value", option_copy->getValue()); } @@ -387,13 +514,21 @@ TEST(OptionCopyTest, optionStringAssignment) { testOptionString(ASSIGN); } +// *************************** OptionVendor *************************** + +/// @brief Test deep copy of option encapsualated by OptionVendor type. +/// +/// @param op_type Copy operation type. void testOptionVendor(const OpType& op_type) { OptionVendorPtr option(new OptionVendor(Option::V4, 2986)); OptionVendorPtr option_copy(new OptionVendor(Option::V6, 1111)); ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + // Modify the vendor id in the original option. option->setVendorId(2222); + + // The vendor id in the copy should not be affected. EXPECT_EQ(2986, option_copy->getVendorId()); } @@ -409,11 +544,19 @@ TEST(OptionCopyTest, optionVendorAssignment) { testOptionVendor(ASSIGN); } +// *********************** OptionVendorClass *************************** + +/// @brief Test deep copy of option encapsualated by OptionVendorClass type. +/// +/// @param op_type Copy operation type. void testOptionVendorClass(const OpType& op_type) { + // Create a DHCPv4 option with a single tuple. OptionVendorClassPtr option(new OptionVendorClass(Option::V4, 2986)); OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE); tuple = "vendor-class-value"; option->setTuple(0, tuple); + + // Create a DHCPv6 option with a single tuple. OptionVendorClassPtr option_copy(new OptionVendorClass(Option::V6, 1111)); OpaqueDataTuple tuple_copy(OpaqueDataTuple::LENGTH_2_BYTES); @@ -422,11 +565,14 @@ void testOptionVendorClass(const OpType& op_type) { ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + // Modify the tuple in the original option and add one more tuple. tuple = "modified-vendor-class-value"; option->setTuple(0, tuple); tuple = "another-modified-vendor-class-value"; option->addTuple(tuple); + // That change shouldn't affect the orginal option. It should still + // contain a single tuple with the original value. ASSERT_EQ(1, option_copy->getTuplesNum()); tuple = option_copy->getTuple(0); EXPECT_TRUE(tuple.equals("vendor-class-value")); @@ -444,27 +590,52 @@ TEST(OptionCopyTest, optionVendorClassAssignment) { testOptionVendorClass(ASSIGN); } +// ************************** Option4ClientFqdn *************************** + +/// @brief Test deep copy of option encapsualated by Option4ClientFqdn or +/// Option6ClientFqdn type. +/// +/// @param op_type Copy operation type. +/// @param option Option to be copied. +/// @param option_copy Destination option. Note that this option may be +/// initially set to a non-null value. For the "copy" and "clone" operations +/// the pointer will be reset, so there is no sense to initialize this +/// object to a non-null value. However, for the assignment testing it is +/// recommended to initialize the option_copy to point to an option having +/// different parameters to verify that all parameters have been overriden +/// by the assignment operation. +/// +/// @tparam OptionType Option4ClientFqdn or Option6ClientFqdn. template void testOptionClientFqdn(const OpType& op_type, boost::shared_ptr& option, boost::shared_ptr& option_copy) { ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + // Modify the values in the original option. option->setDomainName("newname", OptionType::PARTIAL); option->setFlag(OptionType::FLAG_S, false); option->setFlag(OptionType::FLAG_N, true); + // Rcode is carried on the in the DHCPv4 Client FQDN option. + // If the OptionType is pointing to a DHCPv6 option the dynamic + // cast will result in NULL pointer and we'll not check the + // RCODE. Option4ClientFqdnPtr option4 = boost::dynamic_pointer_cast(option); if (option4) { option4->setRcode(64); } + // Verify that common parameters haven't been modified in the + // copied option by the change in the original option. EXPECT_EQ("myname.example.org.", option_copy->getDomainName()); EXPECT_EQ(OptionType::FULL, option_copy->getDomainNameType()); EXPECT_TRUE(option_copy->getFlag(OptionType::FLAG_S)); EXPECT_FALSE(option_copy->getFlag(OptionType::FLAG_N)); + // If we're dealing with DHCPv4 Client FQDN, we also need to + // test RCODE. Option4ClientFqdnPtr option_copy4 = boost::dynamic_pointer_cast(option_copy); if (option_copy4) { @@ -473,6 +644,9 @@ void testOptionClientFqdn(const OpType& op_type, } } +/// @brief Test deep copy of option encapsualated by Option4ClientFqdn type. +/// +/// @param op_type Copy operation type. void testOption4ClientFqdn(const OpType& op_type) { Option4ClientFqdnPtr option(new Option4ClientFqdn(Option4ClientFqdn::FLAG_S, @@ -499,6 +673,11 @@ TEST(OptionCopyTest, option4ClientFqdnAssignment) { testOption4ClientFqdn(ASSIGN); } +// ************************** Option6ClientFqdn *************************** + +/// @brief Test deep copy of option encapsualated by Option6ClientFqdn type. +/// +/// @param op_type Copy operation type. void testOption6ClientFqdn(const OpType& op_type) { Option6ClientFqdnPtr option(new Option6ClientFqdn(Option6ClientFqdn::FLAG_S, @@ -523,15 +702,34 @@ TEST(OptionCopyTest, option6ClientFqdnAssignment) { testOption6ClientFqdn(ASSIGN); } +// **************************** OptionCustom *************************** + +/// @brief Test deep copy of option encapsualated by OptionCustom type. +/// +/// @param op_type Copy operation type. void testOptionCustom(const OpType& op_type) { + // Create option with a single field carrying 16-bits integer. OptionDefinition def("foo", 1, "uint16", true); OptionCustomPtr option(new OptionCustom(def, Option::V4)); - OptionDefinition def_assigned("bar", 10, "record"); - def_assigned.addRecordField("ipv4-address"); - def_assigned.addRecordField("uint32"); - OptionCustomPtr option_copy(new OptionCustom(def_assigned, Option::V6)); + option->addArrayDataField(5555); + + // Create option with two fields carrying IPv4 address and 32-bit + // integer. + OptionDefinition def_copy("bar", 10, "record"); + def_copy.addRecordField("ipv4-address"); + def_copy.addRecordField("uint32"); + OptionCustomPtr option_copy(new OptionCustom(def_copy, Option::V6)); + option_copy->writeAddress(IOAddress("192.0.0.2")); + option_copy->writeInteger(12, 1); ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + + // Modify the original option value. + option->writeInteger(1000); + + // The copied option should not be affected. + ASSERT_EQ(1, option_copy->getDataFieldsNum()); + EXPECT_EQ(5555, option_copy->readInteger()); } TEST(OptionCopyTest, optionCustomConstructor) { @@ -546,6 +744,11 @@ TEST(OptionCopyTest, optionCustomAssignment) { testOptionCustom(ASSIGN); } +// ************************ OptionOpaqueDataTuples *********************** + +/// @brief Test deep copy of option encapsualated by OptionOpaqueDataTuples type. +/// +/// @param op_type Copy operation type. void testOptionOpaqueDataTuples(const OpType& op_type) { OptionOpaqueDataTuplesPtr option(new OptionOpaqueDataTuples(Option::V4, 1)); OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE); @@ -560,11 +763,13 @@ void testOptionOpaqueDataTuples(const OpType& op_type) { ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + // Modify the value in the first tuple and add one more tuple. tuple = "modified-first-tuple"; option->setTuple(0, tuple); tuple = "modified-second-tuple"; - option->addTuple(tuple); + option->setTuple(1, tuple); + // This should not affect the values in the original option. ASSERT_EQ(2, option_copy->getTuplesNum()); EXPECT_TRUE(option_copy->getTuple(0).equals("a string")); EXPECT_TRUE(option_copy->getTuple(1).equals("another string"));