Browse Source

[1959] Implemented changes for 4th part of code review.

Marcin Siodelski 12 years ago
parent
commit
7c7d7c9120

+ 4 - 0
tests/tools/perfdhcp/command_options.cc

@@ -495,6 +495,10 @@ CommandOptions::decodeDuid(const std::string& base) {
         }
         duid_template.push_back(static_cast<uint8_t>(ui));
     }
+    // @todo Get rid of this limitation when we manage add support
+    // for DUIDs other than LLT. Shorter DUIDs may be useful for
+    // server testing purposes.
+    check(duid_template.size() < 6, "DUID must be at least 6 octets long");
     // Assign the new duid only if successfully generated.
     std::swap(duid_template, duid_template_);
 }

+ 17 - 10
tests/tools/perfdhcp/test_control.cc

@@ -298,9 +298,9 @@ OptionPtr
 TestControl::factoryOptionRequestOption6(Option::Universe,
                                          uint16_t,
                                          const OptionBuffer&) {
-    const uint8_t buf_array[] = {
-        0, D6O_NAME_SERVERS,
-        0, D6O_DOMAIN_SEARCH
+    const uint16_t buf_array[] = {
+        htons(D6O_NAME_SERVERS),
+        htons(D6O_DOMAIN_SEARCH)
     };
     OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array));
     return (OptionPtr(new Option(Option::V6, D6O_ORO, buf_with_options)));
@@ -331,7 +331,7 @@ std::vector<uint8_t>
 TestControl::generateMacAddress(uint8_t& randomized) const {
     CommandOptions& options = CommandOptions::instance();
     uint32_t clients_num = options.getClientsNum();
-    if ((clients_num == 0) || (clients_num == 1)) {
+    if (clients_num < 2) {
         return (options.getMacTemplate());
     }
     // Get the base MAC address. We are going to randomize part of it.
@@ -339,11 +339,7 @@ TestControl::generateMacAddress(uint8_t& randomized) const {
     if (mac_addr.size() != HW_ETHER_LEN) {
         isc_throw(BadValue, "invalid MAC address template specified");
     }
-    uint32_t r = random();
-    // The random number must be in the range 0..clients_num-1. This
-    // will guarantee that every client has exactly one random MAC
-    // address assigned.
-    r %= clients_num;
+    uint32_t r = macaddr_gen_->generate();
     randomized = 0;
     // Randomize MAC address octets.
     for (std::vector<uint8_t>::iterator it = mac_addr.end() - 1;
@@ -889,7 +885,10 @@ TestControl::reset() {
     last_sent_ = send_due_;
     last_report_ = send_due_;
     transid_gen_.reset();
-    transid_gen_ = TransidGeneratorPtr(new TransidGenerator());
+    // Actual generators will have to be set later on because we need to
+    // get command line parameters first.
+    setTransidGenerator(NumberGeneratorPtr());
+    setMacAddrGenerator(NumberGeneratorPtr());
     first_packet_serverid_.clear();
     interrupted_ = false;
 }
@@ -907,8 +906,16 @@ TestControl::run() {
     if (options.getIpVersion() == 0) {
         isc_throw(InvalidOperation,
                   "command options must be parsed before running a test");
+    } else if (options.getIpVersion() == 4) {
+        setTransidGenerator(NumberGeneratorPtr(new SequencialGenerator()));
+    } else {
+        setTransidGenerator(NumberGeneratorPtr(new SequencialGenerator(0x00FFFFFF)));
     }
 
+    uint32_t clients_num = options.getClientsNum() == 0 ?
+        1 : options.getClientsNum();
+    setMacAddrGenerator(NumberGeneratorPtr(new SequencialGenerator(clients_num)));
+
     // Diagnostics are command line options mainly.
     printDiagnostics();
     // Option factories have to be registered.

+ 55 - 17
tests/tools/perfdhcp/test_control.h

@@ -127,26 +127,52 @@ public:
         void initSocketData();
     };
 
-    /// \brief Default transaction id generator class.
-    ///
-    /// This is default transaction id generator class. The member
-    /// function is used to generate unique transaction id value.
-    /// Other generator classes should derive from this one to
-    /// override the standard generation algorithm (e.g. unit tests
-    /// override this class wih algorithm that produces more predictable
-    /// transaction id values).
-    class TransidGenerator {
+    /// \brief Number generator class.
+    ///
+    /// This is default numbers generator class. The member function is
+    /// used to generate uint32_t values. Other generator classes should
+    /// derive from this one to implement generation algorithms
+    /// (e.g. sequencial or based on random function).
+    class NumberGenerator {
+    public:
+        /// \brief Generate number.
+        ///
+        /// \return Generate number.
+        virtual uint32_t generate() = 0;
+    };
+
+    /// The default generator pointer.
+    typedef boost::shared_ptr<NumberGenerator> NumberGeneratorPtr;
+
+    /// \brief Sequencial numbers generatorc class.
+    class SequencialGenerator : public NumberGenerator {
     public:
-        /// \brief generate transaction id.
+        /// \Constructor.
         ///
-        /// \return generated transazction id value.
+        /// \param range maximum number generated. If 0 is given then
+        /// range defaults to maximym uint32_t value.
+        SequencialGenerator(uint32_t range = 0xFFFFFFFF) :
+            NumberGenerator(),
+            num_(0),
+            range_(range) {
+            if (range_ == 0) {
+                range_ = 0xFFFFFFFF;
+            }
+        }
+
+        /// \brief Generate number sequencialy.
+        ///
+        /// \return generated number.
         virtual uint32_t generate() {
-            return static_cast<uint32_t>(random() % 0x00FFFFFF);
+            uint32_t num = num_;
+            num_ = (num_ + 1) % range_;
+            return (num);
         }
+    private:
+        uint32_t num_;   ///< Current number.
+        uint32_t range_; ///< Maximum number generated.
     };
 
-    typedef boost::shared_ptr<TransidGenerator> TransidGeneratorPtr;
-
     /// \brief Length of the Ethernet HW address (MAC) in bytes.
     ///
     /// \todo Make this variable length as there are cases when HW
@@ -172,11 +198,22 @@ public:
     /// \brief Set new transaction id generator.
     ///
     /// \param generator generator object to be used.
-    void setTransidGenerator(TransidGeneratorPtr& generator) {
+    void setTransidGenerator(const NumberGeneratorPtr& generator) {
         transid_gen_.reset();
         transid_gen_ = generator;
     }
 
+    /// \brief Set new MAC address generator.
+    ///
+    /// Set numbers generator that will be used to generate various
+    /// MAC addresses to simulate number of clients.
+    ///
+    /// \param generator object to be used.
+    void setMacAddrGenerator(const NumberGeneratorPtr& generator) {
+        macaddr_gen_.reset();
+        macaddr_gen_ = generator;
+    }
+
     // We would really like following methods and members to be private but
     // they have to be accessible for unit-testing. Another, possibly better,
     // solution is to make this class friend of test class but this is not
@@ -337,7 +374,7 @@ protected:
     ///
     /// \return generated transaction id.
     uint32_t generateTransid() {
-        return(transid_gen_->generate());
+        return (transid_gen_->generate());
     }
 
     /// \brief Returns number of exchanges to be started.
@@ -738,7 +775,8 @@ private:
     StatsMgr4Ptr stats_mgr4_;  ///< Statistics Manager 4.
     StatsMgr6Ptr stats_mgr6_;  ///< Statistics Manager 6.
 
-    TransidGeneratorPtr transid_gen_; ///< Transaction id generator.
+    NumberGeneratorPtr transid_gen_; ///< Transaction id generator.
+    NumberGeneratorPtr macaddr_gen_; ///< Numbers generator for MAC address.
 
     /// Buffer holiding server id received in first packet
     dhcp::OptionBuffer first_packet_serverid_;

+ 40 - 14
tests/tools/perfdhcp/tests/command_options_unittest.cc

@@ -264,39 +264,65 @@ TEST_F(CommandOptionsTest, ClientsNum) {
 
 TEST_F(CommandOptionsTest, Base) {
     CommandOptions& opt = CommandOptions::instance();
-    process("perfdhcp -6 -b MAC=10::20::30::40::50::60 "
-            "-l ethx -b duiD=1AB7F5670901FF all");
     uint8_t mac[6] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60 };
     uint8_t duid[14] = {  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
                           0x01, 0x01, 0x01, 0x10, 0x11, 0x1F, 0x14 };
-
-    // Test Mac
+    // Test DUID and MAC together.
+    EXPECT_NO_THROW(process("perfdhcp -b DUID=0101010101010101010110111F14"
+                            " -b MAC=10::20::30::40::50::60"
+                            " -l 127.0.0.1 all"));
     std::vector<uint8_t> v1 = opt.getMacTemplate();
-    ASSERT_EQ(6, v1.size());
+    std::vector<uint8_t> v2 = opt.getDuidTemplate();
+    v2 = opt.getDuidTemplate();
     EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac));
-    // "3x" is invalid value in MAC address
-    EXPECT_THROW(process("perfdhcp -b mac=10::2::3x::4::5::6 -l ethx all"),
-                 isc::InvalidParameter);
-
-    // Test DUID
+    EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid));
+    // Test valid DUID.
     EXPECT_NO_THROW(
         process("perfdhcp -b duid=0101010101010101010110111F14 -l 127.0.0.1 all")
     );
-    std::vector<uint8_t> v2 = opt.getDuidTemplate();
+
     ASSERT_EQ(sizeof(duid) / sizeof(uint8_t), v2.size());
     EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid));
+    // Test mix of upper/lower case letters.
+    EXPECT_NO_THROW(process("perfdhcp -b DuiD=0101010101010101010110111F14"
+                            " -b Mac=10::20::30::40::50::60"
+                            " -l 127.0.0.1 all"));
+    v1 = opt.getMacTemplate();
+    v2 = opt.getDuidTemplate();
+    EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac));
+    EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid));
+    // Use "ether" instead of "mac".
+    EXPECT_NO_THROW(process("perfdhcp -b ether=10::20::30::40::50::60"
+                            " -l 127.0.0.1 all"));
+    v1 = opt.getMacTemplate();
+    EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac));
+    // Use "ETHER" in upper case.
+    EXPECT_NO_THROW(process("perfdhcp -b ETHER=10::20::30::40::50::60"
+                            " -l 127.0.0.1 all"));
+    v1 = opt.getMacTemplate();
+    EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac));
     // "t" is invalid character in DUID
     EXPECT_THROW(process("perfdhcp -6 -l ethx -b "
-                         "duiD=010101010101010101t110111F14 all"),
+                         "duid=010101010101010101t110111F14 all"),
+                 isc::InvalidParameter);
+    // "3x" is invalid value in MAC address
+    EXPECT_THROW(process("perfdhcp -b mac=10::2::3x::4::5::6 -l ethx all"),
                  isc::InvalidParameter);
-
-    // Some more negative test cases
     // Base is not specified
     EXPECT_THROW(process("perfdhcp -b -l ethx all"),
                  isc::InvalidParameter);
     // Typo: should be mac= instead of mc=
     EXPECT_THROW(process("perfdhcp -l ethx -b mc=00:01:02:03::04:05 all"),
                  isc::InvalidParameter);
+    // Too short DUID (< 6).
+    EXPECT_THROW(process("perfdhcp -l ethx -b duid=00010203 all"),
+                 isc::InvalidParameter);
+    // Odd number of digits.
+    EXPECT_THROW(process("perfdhcp -l ethx -b duid=000102030405060 all"),
+                 isc::InvalidParameter);
+    // Too short MAC (!= 6).
+    EXPECT_THROW(process("perfdhcp -l ethx -b mac=00:01:02:04 all"),
+                 isc::InvalidParameter);
 }
 
 TEST_F(CommandOptionsTest, DropTime) {

+ 195 - 64
tests/tools/perfdhcp/tests/test_control_unittest.cc

@@ -15,6 +15,7 @@
 #include <cstddef>
 #include <stdint.h>
 #include <string>
+#include <fstream>
 #include <gtest/gtest.h>
 
 #include <boost/date_time/posix_time/posix_time.hpp>
@@ -45,11 +46,11 @@ public:
     /// the default transaction id generator that generates transaction
     /// ids using random function. This generator will generate values
     /// like: 1,2,3 etc.
-    class IncrementalGenerator : public TestControl::TransidGenerator {
+    class IncrementalGenerator : public TestControl::NumberGenerator {
     public:
         /// \brief Default constructor.
         IncrementalGenerator() :
-            TransidGenerator(),
+            NumberGenerator(),
             transid_(0) {
         }
 
@@ -88,7 +89,11 @@ public:
     using TestControl::setDefaults4;
     using TestControl::setDefaults6;
 
-    NakedTestControl() : TestControl() { };
+    NakedTestControl() : TestControl() {
+        uint32_t clients_num = CommandOptions::instance().getClientsNum() == 0 ?
+            1 : CommandOptions::instance().getClientsNum();
+        setMacAddrGenerator(NumberGeneratorPtr(new TestControl::SequencialGenerator(clients_num)));
+    };
 
 };
 
@@ -109,9 +114,27 @@ public:
     /// \brief Default Constructor
     TestControlTest() { }
 
-    static uint32_t generateTransidIncremental() {
-        static uint32_t transid(1);
-        return (++transid);
+    /// \brief Create packet template file from binary data.
+    ///
+    /// Function creates file containing data from the provided buffer
+    /// in hexadecimal format.
+    /// \param filename template file to be created.
+    /// \param buffer with binary datato be stored in file.
+    /// \return true if file creation successful.
+    bool createTemplateFile(const std::string& filename,
+                            const std::vector<uint8_t>& buf) const {
+        std::ofstream temp_file;
+        temp_file.open(filename.c_str(), ios::out | ios::trunc);
+        if (!temp_file.is_open()) {
+            return (false);
+        }
+        for (int i = 0; i < buf.size(); ++i) {
+            int first_digit = buf[i] / 16;
+            int second_digit = buf[i] % 16;
+            temp_file << std::hex << first_digit << second_digit << std::dec;
+        }
+        temp_file.close();
+        return (true);
     }
 
     /// \brief Get local loopback interface name.
@@ -130,14 +153,8 @@ public:
         for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin();
              iface != ifaces.end();
              ++iface) {
-            for (IfaceMgr::AddressCollection::const_iterator addr_it =
-                     iface->getAddresses().begin();
-                 addr_it != iface->getAddresses().end();
-                 ++addr_it) {
-                if (asiolink::IOAddress("127.0.0.1").getAddress() ==
-                    addr_it->getAddress()) {
-                    return (iface->getName());
-                }
+            if (iface->flag_loopback_) {
+                return (iface->getName());
             }
         }
         return ("");
@@ -147,7 +164,7 @@ public:
     ///
     /// This method iterates through options provided in the buffer
     /// and matches them with the options specified with first parameter.
-    /// Options in both vectors may be layed in different order.
+    /// Options in both vectors may be laid in different order.
     ///
     /// \param requested_options reference buffer with options.
     /// \param buf test buffer with options that will be matched.
@@ -168,6 +185,38 @@ public:
         return (matched_num);
     }
 
+    /// \brief Match requested DHCPv6 options in the buffer with given list.
+    ///
+    /// This method iterates through options provided in the buffer and
+    /// matches them with the options specified with first parameter.
+    /// Options in both vectors ma be laid in different order.
+    ///
+    /// \param requested_options reference buffer with options.
+    /// \param buf test buffer with options that will be matched.
+    /// \return number of options from the buffer matched with options in
+    /// the reference buffer or -1 if error occured.
+    int matchRequestedOptions6(const dhcp::OptionBuffer& requested_options,
+                               const dhcp::OptionBuffer& buf) const {
+        // Sanity check.
+        if ((requested_options.size() % 2 != 0) ||
+            (buf.size() % 2 != 0)) {
+            return -1;
+        }
+        size_t matched_num = 0;
+        for (size_t i = 0; i < buf.size(); i += 2) {
+            for (int j = 0; j < requested_options.size(); j += 2) {
+                uint16_t opt_i = buf[i + 1] << 8 + buf[i];
+                uint16_t opt_j = buf[j + 1] << 8 + buf[j];
+                if (opt_i == opt_j) {
+                    // Requested option has been found.
+                    ++matched_num;
+                    break;
+                }
+            }
+        }
+        return (matched_num);
+    }
+
     /// \brief Calculate the maximum vectors' mismatch position.
     ///
     /// This helper function calculates the maximum mismatch position
@@ -180,22 +229,20 @@ public:
     /// on two last positions so the returned value will be 2 and so on.
     ///
     /// \param clients_num number of simulated clinets
-    /// \param randomization range - for either MAC or DUID it is 6
     /// \return maximum mismatch position
-    int unequalOctetPosition(const int clients_num,
-                             const size_t random_size) const {
-        int unequal_pos = 0;
-        int n = clients_num - 1;
-        if (n > 0) {
-            for (int i = 0; i < random_size; ++i) {
-                if (n < 256) {
-                    unequal_pos = i + 1;
-                    break;
-                }
-                n %= 256;
-            }
+    int unequalOctetPosition(int clients_num) const {
+        if (!clients_num) {
+            return (0);
         }
-        return (unequal_pos);
+        clients_num--;
+
+        int cnt = 0;
+        while (clients_num) {
+            clients_num >>= 8;
+            ++cnt;
+        }
+
+        return (cnt);
     }
 
     /// brief Test generation of mulitple DUIDs
@@ -212,32 +259,32 @@ public:
     /// and do not change if single client is simulated.
     void testDuid() const {
         int clients_num = CommandOptions::instance().getClientsNum();
+        // Initialize Test Control class.
+        NakedTestControl tc;
         // The old duid will be holding the previously generated DUID.
         // It will be used to compare against the new one. If we have
         // multiple clients we want to make sure that duids differ.
-        Duid old_duid(CommandOptions::instance().getDuidTemplate());
+        uint8_t randomized = 0;
+        Duid old_duid(tc.generateDuid(randomized));
         Duid new_duid(0);
         // total_dist shows the total difference between generated duid.
         // It has to be greater than zero if multiple clients are simulated.
         size_t total_dist = 0;
+        // Number of unique DUIDs.
+        size_t unique_duids = 0;
         // Holds the position if the octet on which two DUIDS can be different.
         // If number of clients is 256 or less it is last DUID octet (except for
         // single client when subsequent DUIDs have to be equal). If number of
         // clients is between 257 and 65536 the last two octets can differ etc.
-        const size_t mac_addr_size = 6;
-        int unequal_pos = unequalOctetPosition(clients_num, mac_addr_size);
-
-        // Initialize Test Control class.
-        NakedTestControl tc;
+        int unequal_pos = unequalOctetPosition(clients_num);
+        // Keep generated DUIDs in this container.
+        std::list<std::vector<uint8_t> > duids;
         // Perform number of iterations to generate number of DUIDs.
-        // If single clinet is involved, try multiple times (10) and
-        // see if the same DUID is always generated.
-        for (int i = 0; i < clients_num * 10; ++i) {
+        for (int i = 0; i < 10 * clients_num; ++i) {
             if (new_duid.empty()) {
                 new_duid = old_duid;
             } else {
                 std::swap(old_duid, new_duid);
-                uint8_t randomized = 0;
                 new_duid = tc.generateDuid(randomized);
             }
             // The DUID-LLT is expected to start with DUID_LLT value
@@ -259,8 +306,8 @@ public:
             uint32_t duid_time = 0;
             // Pick 4 bytes of the time from generated DUID and put them
             // in reverse order (in DUID they are stored in network order).
-            for (int i = 4; i < 8; ++i) {
-                duid_time |= new_duid[i] << (i - 4);
+            for (int j = 4; j < 8; ++j) {
+                duid_time |= new_duid[j] << (j - 4);
             }
             // Calculate the duration since epoch time.
             ptime now = microsec_clock::universal_time();
@@ -288,11 +335,35 @@ public:
             // Mismatch may have occured on the DUID octet position
             // up to calculated earlier unequal_pos.
             ASSERT_LE(mismatch_dist, unequal_pos);
+            // unique will inform if tested DUID is unique.
+            bool unique = true;
+            for (std::list<std::vector<uint8_t> >::const_iterator it =
+                     duids.begin();
+                 it != duids.end(); ++it) {
+                // DUIDs should be of the same size if we want to compare them.
+                ASSERT_EQ(new_duid.size(), it->size());
+                // Check if DUID is unique.
+                if (std::equal(new_duid.begin(), new_duid.end(), it->begin())) {
+                    unique = false;
+                }
+            }
+            // Expecting that DUIDs will be unique only when
+            // first clients-num iterations is performed.
+            // After that, DUIDs become non unique.
+            if (unique) {
+                ++unique_duids;
+            }
+            // For number of iterations equal to clients_num,2*clients_num
+            // 3*clients_num ... we have to have number of unique duids
+            // equal to clients_num.
+            if ((i != 0) && (i % clients_num == 0)) {
+                ASSERT_EQ(clients_num, unique_duids);
+            }
+            // Remember generated DUID.
+            duids.push_back(new_duid);
         }
         // If we have more than one client at least one mismatch occured.
-        if (clients_num > 1) {
-            EXPECT_GT(total_dist, 0);
-        } else {
+        if (clients_num < 2) {
             EXPECT_EQ(0, total_dist);
         }
     }
@@ -327,10 +398,10 @@ public:
 
         // Incremental transaction id generator will generate
         // predictable values of transaction id for each iteration.
-        // This is important because we need to simulate reponses
+        // This is important because we need to simulate responses
         // from the server and use the same transaction ids as in
         // packets sent by client.
-        TestControl::TransidGeneratorPtr
+        TestControl::NumberGeneratorPtr
             generator(new NakedTestControl::IncrementalGenerator());
         tc.setTransidGenerator(generator);
         // Socket is needed to send packets through the interface.
@@ -393,7 +464,7 @@ public:
         // This is important because we need to simulate reponses
         // from the server and use the same transaction ids as in
         // packets sent by client.
-        TestControl::TransidGeneratorPtr
+        TestControl::NumberGeneratorPtr
             generator(new NakedTestControl::IncrementalGenerator());
         tc.setTransidGenerator(generator);
         // Socket is needed to send packets through the interface.
@@ -445,10 +516,14 @@ public:
         // octet (except for single client when subsequent MAC addresses
         // have to be equal). If number of clients is between 257 and 65536
         // the last two octets can differ etc.
-        int unequal_pos = unequalOctetPosition(clients_num, old_mac.size());;
-
+        int unequal_pos = unequalOctetPosition(clients_num);
+        // Number of unique MACs.
+        size_t unique_macs = 0;
+        // Initialize Test Controller.
         NakedTestControl tc;
         size_t total_dist = 0;
+        // Keep generated MACs in this container.
+        std::list<std::vector<uint8_t> > macs;
         // Do many iterations to generate and test MAC address values.
         for (int i = 0; i < clients_num * 10; ++i) {
             // Generate new MAC address.
@@ -470,11 +545,35 @@ public:
             // Mismatch may have occured on the MAC address'es octet position
             // up to calculated earlier unequal_pos.
             ASSERT_LE(mismatch_dist, unequal_pos);
+            // unique will inform if tested DUID is unique.
+            bool unique = true;
+            for (std::list<std::vector<uint8_t> >::const_iterator it =
+                     macs.begin();
+                 it != macs.end(); ++it) {
+                // MACs should be of the same size if we want to compare them.
+                ASSERT_EQ(new_mac.size(), it->size());
+                // Check if MAC is unique.
+                if (std::equal(new_mac.begin(), new_mac.end(), it->begin())) {
+                    unique = false;
+                }
+            }
+            // Expecting that MACs will be unique only when
+            // first clients-num iterations is performed.
+            // After that, MACs become non unique.
+            if (unique) {
+                ++unique_macs;
+            }
+            // For number of iterations equal to clients_num,2*clients_num
+            // 3*clients_num ... we have to have number of unique MACs
+            // equal to clients_num.
+            if ((i != 0) && (i % clients_num == 0)) {
+                ASSERT_EQ(clients_num, unique_macs);
+            }
+            // Remember generated MAC.
+            macs.push_back(new_mac);
+
         }
-        // If we have more than one client at least one mismatch occured.
-        if (clients_num > 1) {
-            EXPECT_GT(total_dist, 0);
-        } else {
+        if (clients_num < 2)  {
             EXPECT_EQ(total_dist, 0);
         }
     }
@@ -489,6 +588,10 @@ public:
     }
 
 private:
+    /// \brief Create DHCPv4 OFFER packet.
+    ///
+    /// \param transid transaction id.
+    /// \return instance of the packet.
     boost::shared_ptr<Pkt4>
     createOfferPkt4(uint32_t transid) const {
         boost::shared_ptr<Pkt4> offer(new Pkt4(DHCPOFFER, transid));
@@ -504,6 +607,10 @@ private:
         return (offer);
     }
 
+    /// \brief Create DHCPv6 ADVERTISE packet.
+    ///
+    /// \param transid transaction id.
+    /// \return instance of the packet.
     boost::shared_ptr<Pkt6>
     createAdvertisePkt6(uint32_t transid) const {
         OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
@@ -664,10 +771,12 @@ TEST_F(TestControlTest, Options6) {
     // Validate the D6O_ORO (Option Request Option).
     OptionPtr opt_oro(Option::factory(Option::V6, D6O_ORO));
     // Prepare the reference buffer with requested options.
-    const uint8_t requested_options[] = {
-        0, D6O_NAME_SERVERS,
-        0, D6O_DOMAIN_SEARCH
+    const uint16_t requested_options[] = {
+        htons(D6O_NAME_SERVERS),
+        htons(D6O_DOMAIN_SEARCH)
     };
+    int requested_options_num =
+        sizeof(requested_options) / sizeof(requested_options[0]);
     OptionBuffer
         requested_options_ref(requested_options,
                               requested_options + sizeof(requested_options));
@@ -677,9 +786,9 @@ TEST_F(TestControlTest, Options6) {
     // the same for comparison.
     EXPECT_EQ(requested_options_ref.size(), requested_options_buf.size());
     // Check if all options in the buffer are matched with reference buffer.
-    size_t matched_num = matchRequestedOptions(requested_options_ref,
-                                               requested_options_buf);
-    EXPECT_EQ(sizeof(requested_options), matched_num);
+    size_t matched_num = matchRequestedOptions6(requested_options_ref,
+                                                requested_options_buf);
+    EXPECT_EQ(requested_options_num, matched_num);
 
     // Validate the D6O_IA_NA option.
     OptionPtr opt_ia_na(Option::factory(Option::V6, D6O_IA_NA));
@@ -698,7 +807,7 @@ TEST_F(TestControlTest, Options6) {
     EXPECT_TRUE(std::equal(opt_ia_na_ref.begin(), opt_ia_na_ref.end(),
                            opt_ia_na_buf.begin()));
 
-    // TODO: Add more tests for IA address options.
+    // @todo Add more tests for IA address options.
 }
 
 TEST_F(TestControlTest, Packet4) {
@@ -826,7 +935,8 @@ TEST_F(TestControlTest, Packet6Exchange) {
     // Set number of received packets equal to number of iterations.
     // This simulates no packet drops.
     bool use_templates = false;
-    testPkt6Exchange(iterations_num, iterations_num, use_templates, iterations_performed);
+    testPkt6Exchange(iterations_num, iterations_num, use_templates,
+                     iterations_performed);
     // Actual number of iterations should be 10.
     EXPECT_EQ(10, iterations_performed);
 
@@ -841,20 +951,40 @@ TEST_F(TestControlTest, Packet6Exchange) {
     // then test should be interrupted and actual number of iterations will
     // be 6.
     const int received_num = 3;
-    testPkt6Exchange(iterations_num, received_num, use_templates, iterations_performed);
+    testPkt6Exchange(iterations_num, received_num, use_templates,
+                     iterations_performed);
     EXPECT_EQ(6, iterations_performed);
 }
 
 TEST_F(TestControlTest, PacketTemplates) {
+    std::vector<uint8_t> template1(256);
+    std::string file1("../templates/test1.hex");
+    std::vector<uint8_t> template2(233);
+    std::string file2("../templates/test2.hex");
+    for (int i = 0; i < template1.size(); ++i) {
+        template1[i] = static_cast<uint8_t>(random() % 256);
+    }
+    for (int i = 0; i < template2.size(); ++i) {
+        template2[i] = static_cast<uint8_t>(random() % 256);
+    }
+    ASSERT_TRUE(createTemplateFile(file1, template1));
+    ASSERT_TRUE(createTemplateFile(file2, template2));
     CommandOptions& options = CommandOptions::instance();
     NakedTestControl tc;
 
     ASSERT_NO_THROW(
         processCmdLine("perfdhcp -l 127.0.0.1"
-                       " -T ../templates/discover-example.hex"
-                       " -T ../templates/request4-example.hex all")
+                       " -T " + file1 + " -T " + file2 + " all")
     );
     ASSERT_NO_THROW(tc.initPacketTemplates());
+    TestControl::TemplateBuffer buf1;
+    TestControl::TemplateBuffer buf2;
+    ASSERT_NO_THROW(buf1 = tc.getTemplateBuffer(0));
+    ASSERT_NO_THROW(buf2 = tc.getTemplateBuffer(1));
+    ASSERT_EQ(template1.size(), buf1.size());
+    ASSERT_EQ(template2.size(), buf2.size());
+    EXPECT_TRUE(std::equal(template1.begin(), template1.end(), buf1.begin()));
+    EXPECT_TRUE(std::equal(template2.begin(), template2.end(), buf2.begin()));
 }
 
 TEST_F(TestControlTest, RateControl) {
@@ -879,4 +1009,5 @@ TEST_F(TestControlTest, RateControl) {
     xchgs_num = tc2.getNextExchangesNum();
     EXPECT_GT(xchgs_num, 0);
     EXPECT_LT(xchgs_num, options.getAggressivity());
+    // @todo add more thorough checks for rate values.
 }