Browse Source

[master] Merge branch 'trac3173'

Marcin Siodelski 11 years ago
parent
commit
4cc844f7cc

+ 93 - 10
tests/tools/perfdhcp/command_options.cc

@@ -32,6 +32,63 @@ using namespace isc;
 namespace isc {
 namespace perfdhcp {
 
+CommandOptions::LeaseType::LeaseType()
+    : type_(ADDRESS) {
+}
+
+CommandOptions::LeaseType::LeaseType(const Type lease_type)
+    : type_(lease_type) {
+}
+
+bool
+CommandOptions::LeaseType::is(const Type lease_type) const {
+    return (lease_type == type_);
+}
+
+bool
+CommandOptions::LeaseType::includes(const Type lease_type) const {
+    return (is(ADDRESS_AND_PREFIX) || (lease_type == type_));
+}
+
+void
+CommandOptions::LeaseType::set(const Type lease_type) {
+    type_ = lease_type;
+}
+
+void
+CommandOptions::LeaseType::fromCommandLine(const std::string& cmd_line_arg) {
+    if (cmd_line_arg == "address-only") {
+        type_ = ADDRESS;
+
+    } else if (cmd_line_arg == "prefix-only") {
+        type_ = PREFIX;
+
+    } else if (cmd_line_arg == "address-and-prefix") {
+        type_ = ADDRESS_AND_PREFIX;
+
+    } else {
+        isc_throw(isc::InvalidParameter, "value of lease-type: -e<lease-type>,"
+                  " must be one of the following: 'address-only' or"
+                  " 'prefix-only'");
+    }
+}
+
+std::string
+CommandOptions::LeaseType::toText() const {
+    switch (type_) {
+    case ADDRESS:
+        return ("address-only (IA_NA option added to the client's request)");
+    case PREFIX:
+        return ("prefix-only (IA_PD option added to the client's request)");
+    case ADDRESS_AND_PREFIX:
+        return ("address-and-prefix (Both IA_NA and IA_PD options added to the"
+                " client's request)");
+    default:
+        isc_throw(Unexpected, "internal error: undefined lease type code when"
+                  " returning textual representation of the lease type");
+    }
+}
+
 CommandOptions&
 CommandOptions::instance() {
     static CommandOptions options;
@@ -52,6 +109,7 @@ CommandOptions::reset() {
     // will need to reset all members many times to perform unit tests
     ipversion_ = 0;
     exchange_mode_ = DORA_SARR;
+    lease_type_.set(LeaseType::ADDRESS);
     rate_ = 0;
     report_delay_ = 0;
     clients_num_ = 0;
@@ -150,7 +208,7 @@ CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) {
     // In this section we collect argument values from command line
     // they will be tuned and validated elsewhere
     while((opt = getopt(argc, argv, "hv46r:t:R:b:n:p:d:D:l:P:a:L:"
-                        "s:iBc1T:X:O:E:S:I:x:w:")) != -1) {
+                        "s:iBc1T:X:O:E:S:I:x:w:e:")) != -1) {
         stream << " -" << static_cast<char>(opt);
         if (optarg) {
             stream << " " << optarg;
@@ -232,6 +290,10 @@ CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) {
             }
             break;
 
+        case 'e':
+            initLeaseType();
+            break;
+
         case 'E':
             elp_offset_ = nonNegativeInteger("value of time-offset: -E<value>"
                                              " must not be a negative integer");
@@ -438,7 +500,7 @@ CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) {
 
     // If DUID is not specified from command line we need to
     // generate one.
-    if (duid_template_.size() == 0) {
+    if (duid_template_.empty()) {
         generateDuidTemplate();
     }
     return (false);
@@ -506,9 +568,9 @@ CommandOptions::decodeMac(const std::string& base) {
     mac_template_.clear();
     // Get pieces of MAC address separated with : (or even ::)
     while (std::getline(s1, token, ':')) {
-        unsigned int ui = 0;
         // Convert token to byte value using std::istringstream
         if (token.length() > 0) {
+            unsigned int ui = 0;
             try {
                 // Do actual conversion
                 ui = convertHexString(token);
@@ -620,6 +682,12 @@ CommandOptions::validate() const {
           "-6 (IPv6) must be set to use -c");
     check((getExchangeMode() == DO_SA) && (getNumRequests().size() > 1),
           "second -n<num-request> is not compatible with -i");
+    check((getIpVersion() == 4) && !getLeaseType().is(LeaseType::ADDRESS),
+          "-6 option must be used if lease type other than '-e address-only'"
+          " is specified");
+    check(!getTemplateFiles().empty() &&
+          !getLeaseType().is(LeaseType::ADDRESS),
+          "template files may be only used with '-e address-only'");
     check((getExchangeMode() == DO_SA) && (getDropTime()[1] != 1.),
           "second -d<drop-time> is not compatible with -i");
     check((getExchangeMode() == DO_SA) &&
@@ -706,6 +774,12 @@ CommandOptions::nonEmptyString(const std::string& errmsg) const {
 }
 
 void
+CommandOptions::initLeaseType() {
+    std::string lease_type_arg = optarg;
+    lease_type_.fromCommandLine(lease_type_arg);
+}
+
+void
 CommandOptions::printCommandLine() const {
     std::cout << "IPv" << static_cast<int>(ipversion_) << std::endl;
     if (exchange_mode_ == DO_SA) {
@@ -715,6 +789,7 @@ CommandOptions::printCommandLine() const {
             std::cout << "SOLICIT-ADVERETISE only" << std::endl;
         }
     }
+    std::cout << "lease-type=" << getLeaseType().toText() << std::endl;
     if (rate_ != 0) {
         std::cout << "rate[1/s]=" << rate_ <<  std::endl;
     }
@@ -800,13 +875,13 @@ CommandOptions::printCommandLine() const {
 void
 CommandOptions::usage() const {
     std::cout <<
-        "perfdhcp [-hv] [-4|-6] [-r<rate>] [-t<report>] [-R<range>] [-b<base>]\n"
-        "    [-n<num-request>] [-p<test-period>] [-d<drop-time>] [-D<max-drop>]\n"
-        "    [-l<local-addr|interface>] [-P<preload>] [-a<aggressivity>]\n"
-        "    [-L<local-port>] [-s<seed>] [-i] [-B] [-c] [-1]\n"
-        "    [-T<template-file>] [-X<xid-offset>] [-O<random-offset]\n"
-        "    [-E<time-offset>] [-S<srvid-offset>] [-I<ip-offset>]\n"
-        "    [-x<diagnostic-selector>] [-w<wrapped>] [server]\n"
+        "perfdhcp [-hv] [-4|-6] [-e<lease-type>] [-r<rate>] [-t<report>]\n"
+        "    [-R<range>] [-b<base>] [-n<num-request>] [-p<test-period>]\n"
+        "    [-d<drop-time>] [-D<max-drop>] [-l<local-addr|interface>]\n"
+        "    [-P<preload>] [-a<aggressivity>] [-L<local-port>] [-s<seed>]\n"
+        "    [-i] [-B] [-c] [-1] [-T<template-file>] [-X<xid-offset>]\n"
+        "    [-O<random-offset] [-E<time-offset>] [-S<srvid-offset>]\n"
+        "    [-I<ip-offset>] [-x<diagnostic-selector>] [-w<wrapped>] [server]\n"
         "\n"
         "The [server] argument is the name/address of the DHCP server to\n"
         "contact.  For DHCPv4 operation, exchanges are initiated by\n"
@@ -838,6 +913,14 @@ CommandOptions::usage() const {
         "-d<drop-time>: Specify the time after which a requeqst is treated as\n"
         "    having been lost.  The value is given in seconds and may contain a\n"
         "    fractional component.  The default is 1 second.\n"
+        "-e<lease-type>: A type of lease being requested from the server. It\n"
+        "    may be one of the following: address-only, prefix-only or\n"
+        "    address-and-prefix. The address-only indicates that the regular\n"
+        "    address (v4 or v6) will be requested. The prefix-only indicates\n"
+        "    that the IPv6 prefix will be requested. The address-and-prefix\n"
+        "    indicates that both IPv6 address and prefix will be requested.\n"
+        "    The '-e prefix-only' and -'e address-and-prefix' must not be\n"
+        "    used with -4.\n"
         "-E<time-offset>: Offset of the (DHCPv4) secs field / (DHCPv6)\n"
         "    elapsed-time option in the (second/request) template.\n"
         "    The value 0 disables it.\n"

+ 89 - 3
tests/tools/perfdhcp/command_options.h

@@ -1,3 +1,4 @@
+
 // Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
@@ -30,6 +31,79 @@ namespace perfdhcp {
 ///
 class CommandOptions : public boost::noncopyable {
 public:
+
+    /// \brief A class encapsulating the type of lease being requested from the
+    /// server.
+    ///
+    /// This class comprises convenience functions to convert the lease type
+    /// to the textual format and to match the appropriate lease type with the
+    /// value of the -e<lease-type> parameter specified from the command line.
+    class LeaseType {
+    public:
+
+        /// The lease type code.
+        enum Type {
+            ADDRESS,
+            PREFIX,
+            ADDRESS_AND_PREFIX
+        };
+
+        LeaseType();
+
+        /// \brief Constructor from lease type code.
+        ///
+        /// \param lease_type A lease type code.
+        LeaseType(const Type lease_type);
+
+        /// \brief Checks if lease type has the specified code.
+        ///
+        /// \param lease_type A lease type code to be checked.
+        ///
+        /// \return true if lease type is matched with the specified code.
+        bool is(const Type lease_type) const;
+
+        /// \brief Checks if lease type implies request for the address,
+        /// prefix (or both) as specified by the function argument.
+        ///
+        /// This is a convenience function to check that, for the lease type
+        /// specified from the command line, the address or prefix
+        /// (IA_NA or IA_PD) option should be sent to the server.
+        /// For example, if user specified '-e address-and-prefix' in the
+        /// command line this function will return true for both ADDRESS
+        /// and PREFIX, because both address and prefix is requested from
+        /// the server.
+        ///
+        /// \param lease_type A lease type.
+        ///
+        /// \return true if the lease type implies creation of the address,
+        /// prefix or both as specified by the argument.
+        bool includes(const Type lease_type) const;
+
+        /// \brief Sets the lease type code.
+        ///
+        /// \param lease_type A lease type code.
+        void set(const Type lease_type);
+
+        /// \brief Sets the lease type from the command line argument.
+        ///
+        /// \param cmd_line_arg An argument specified in the command line
+        /// as -e<lease-type>:
+        /// - address-only
+        /// - prefix-only
+        ///
+        /// \throw isc::InvalidParameter if the specified argument is invalid.
+        void fromCommandLine(const std::string& cmd_line_arg);
+
+        /// \brief Return textual representation of the lease type.
+        ///
+        /// \return A textual representation of the lease type.
+        std::string toText() const;
+
+    private:
+        Type type_; ///< A lease type code.
+
+    };
+
     /// 2-way (cmd line param -i) or 4-way exchanges
     enum ExchangeMode {
         DO_SA,
@@ -71,6 +145,11 @@ public:
     /// \return packet exchange mode.
     ExchangeMode getExchangeMode() const { return exchange_mode_; }
 
+    /// \ brief Returns the type of lease being requested.
+    ///
+    /// \return type of lease being requested by perfdhcp.
+    LeaseType getLeaseType() const { return (lease_type_); }
+
     /// \brief Returns echange rate.
     ///
     /// \return exchange rate per second.
@@ -300,6 +379,11 @@ private:
     /// \throw InvalidParameter if string is empty.
     std::string nonEmptyString(const std::string& errmsg) const;
 
+    /// \brief Decodes the lease type requested by perfdhcp from optarg.
+    ///
+    /// \throw InvalidParameter if lease type value specified is invalid.
+    void initLeaseType();
+
     /// \brief Set number of clients.
     ///
     /// Interprets the getopt() "opt" global variable as the number of clients
@@ -373,6 +457,8 @@ private:
     uint8_t ipversion_;
     /// Packet exchange mode (e.g. DORA/SARR)
     ExchangeMode exchange_mode_;
+    /// Lease Type to be obtained: address only, IPv6 prefix only.
+    LeaseType lease_type_;
     /// Rate in exchange per second
     int rate_;
     /// Delay between generation of two consecutive
@@ -396,7 +482,7 @@ private:
     /// Indicates number of -d<value> parameters specified by user.
     /// If this value goes above 2, command line parsing fails.
     uint8_t drop_time_set_;
-    /// Time to elapse before request is lost. The fisrt value of
+    /// Time to elapse before request is lost. The first value of
     /// two-element vector refers to DO/SA exchanges,
     /// second value refers to RA/RR. Default values are { 1, 1 }
     std::vector<double> drop_time_;
@@ -433,12 +519,12 @@ private:
     /// Indicates that we take server id from first received packet.
     bool use_first_;
     /// Packet template file names. These files store template packets
-    /// that are used for initiating echanges. Template packets
+    /// that are used for initiating exchanges. Template packets
     /// read from files are later tuned with variable data.
     std::vector<std::string> template_file_;
     /// Offset of transaction id in template files. First vector
     /// element points to offset for DISCOVER/SOLICIT messages,
-    /// second element points to trasaction id offset for
+    /// second element points to transaction id offset for
     /// REQUEST messages
     std::vector<int> xid_offset_;
     /// Random value offset in templates. Random value offset

+ 4 - 3
tests/tools/perfdhcp/stats_mgr.h

@@ -260,6 +260,7 @@ public:
         /// assumed dropped. Negative value disables it.
         /// \param archive_enabled if true packets archive mode is enabled.
         /// In this mode all packets are stored throughout the test execution.
+        /// \param boot_time Holds the timestamp when perfdhcp has been started.
         ExchangeStats(const ExchangeType xchg_type,
                       const double drop_time,
                       const bool archive_enabled,
@@ -1183,7 +1184,7 @@ public:
     /// \throw isc::InvalidOperation if no exchange type added to
     /// track statistics.
      void printStats() const {
-        if (exchanges_.size() == 0) {
+        if (exchanges_.empty()) {
             isc_throw(isc::InvalidOperation,
                       "no exchange type added for tracking");
         }
@@ -1238,7 +1239,7 @@ public:
     /// \throw isc::InvalidOperation if no exchange type added to
     /// track statistics or packets archive mode is disabled.
     void printTimestamps() const {
-        if (exchanges_.size() == 0) {
+        if (exchanges_.empty()) {
             isc_throw(isc::InvalidOperation,
                       "no exchange type added for tracking");
         }
@@ -1261,7 +1262,7 @@ public:
     ///
     /// \throw isc::InvalidOperation if no custom counters added for tracking.
     void printCustomCounters() const {
-        if (custom_counters_.size() == 0) {
+        if (custom_counters_.empty()) {
             isc_throw(isc::InvalidOperation, "no custom counters specified");
         }
         for (CustomCountersMapIterator it = custom_counters_.begin();

+ 83 - 19
tests/tools/perfdhcp/test_control.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -97,6 +97,36 @@ TestControl::TestControl() {
     reset();
 }
 
+void
+TestControl::copyIaOptions(const Pkt6Ptr& pkt_from, Pkt6Ptr& pkt_to) {
+    if (!pkt_from || !pkt_to) {
+        isc_throw(BadValue, "NULL pointers must not be specified as arguments"
+                  " for the copyIaOptions function");
+    }
+    // IA_NA
+    if (CommandOptions::instance().getLeaseType()
+        .includes(CommandOptions::LeaseType::ADDRESS)) {
+        OptionPtr option = pkt_from->getOption(D6O_IA_NA);
+        if (!option) {
+            isc_throw(OptionNotFound, "IA_NA option not found in the"
+                      " server's response");
+        }
+        pkt_to->addOption(option);
+    }
+    // IA_PD
+    if (CommandOptions::instance().getLeaseType()
+        .includes(CommandOptions::LeaseType::PREFIX)) {
+        OptionPtr option = pkt_from->getOption(D6O_IA_PD);
+        if (!option) {
+            isc_throw(OptionNotFound, "IA_PD option not found in the"
+                      " server's response");
+        }
+        pkt_to->addOption(option);
+    }
+
+
+}
+
 std::string
 TestControl::byte2Hex(const uint8_t b) const {
     const int b1 = b / 16;
@@ -290,6 +320,22 @@ TestControl::factoryIana6(Option::Universe, uint16_t,
 }
 
 OptionPtr
+TestControl::factoryIapd6(Option::Universe, uint16_t,
+                          const OptionBuffer& buf) {
+    // @todo allow different values of T1, T2 and IAID.
+    static const uint8_t buf_array[] = {
+        0, 0, 0, 1,                     // IAID = 1
+        0, 0, 3600 >> 8, 3600 & 0xff,   // T1 = 3600
+        0, 0, 5400 >> 8, 5400 & 0xff,   // T2 = 5400
+    };
+    OptionBuffer buf_ia_pd(buf_array, buf_array + sizeof(buf_array));
+    // Append sub-options to IA_PD.
+    buf_ia_pd.insert(buf_ia_pd.end(), buf.begin(), buf.end());
+    return (OptionPtr(new Option(Option::V6, D6O_IA_PD, buf_ia_pd)));
+}
+
+
+OptionPtr
 TestControl::factoryRapidCommit6(Option::Universe, uint16_t,
                                  const OptionBuffer&) {
     return (OptionPtr(new Option(Option::V6, D6O_RAPID_COMMIT, OptionBuffer())));
@@ -412,11 +458,11 @@ TestControl::getElapsedTime(const T& pkt1, const T& pkt2) {
 uint64_t
 TestControl::getNextExchangesNum() const {
     CommandOptions& options = CommandOptions::instance();
-    // Reset number of exchanges.
-    uint64_t due_exchanges = 0;
     // Get current time.
     ptime now(microsec_clock::universal_time());
     if (now >= send_due_) {
+        // Reset number of exchanges.
+        uint64_t due_exchanges = 0;
         // If rate is specified from the command line we have to
         // synchornize with it.
         if (options.getRate() != 0) {
@@ -594,15 +640,15 @@ TestControl::openSocket() const {
     uint16_t port = options.getLocalPort();
     int sock = 0;
 
-    uint8_t family = (options.getIpVersion() == 6) ? AF_INET6 : AF_INET; 
+    uint8_t family = (options.getIpVersion() == 6) ? AF_INET6 : AF_INET;
     IOAddress remoteaddr(servername);
-    
+
     // Check for mismatch between IP option and server address
     if (family != remoteaddr.getFamily()) {
-        isc_throw(InvalidParameter, 
-                  "Values for IP version: " <<  
+        isc_throw(InvalidParameter,
+                  "Values for IP version: " <<
                   static_cast<unsigned int>(options.getIpVersion()) <<
-                  " and server address: " << servername << " are mismatched."); 
+                  " and server address: " << servername << " are mismatched.");
     }
 
     if (port == 0) {
@@ -691,7 +737,7 @@ TestControl::sendPackets(const TestControlSocket& socket,
         if (options.getIpVersion() == 4) {
             // No template packets means that no -T option was specified.
             // We have to build packets ourselfs.
-            if (template_buffers_.size() == 0) {
+            if (template_buffers_.empty()) {
                 sendDiscover4(socket, preload);
             } else {
                 // @todo add defines for packet type index that can be
@@ -701,7 +747,7 @@ TestControl::sendPackets(const TestControlSocket& socket,
         } else {
             // No template packets means that no -T option was specified.
             // We have to build packets ourselfs.
-            if (template_buffers_.size() == 0) {
+            if (template_buffers_.empty()) {
                 sendSolicit6(socket, preload);
             } else {
                 // @todo add defines for packet type index that can be
@@ -920,7 +966,7 @@ TestControl::readPacketTemplate(const std::string& file_name) {
     // Expect even number of digits.
     if (hex_digits.size() % 2 != 0) {
         isc_throw(OutOfRange, "odd number of digits in template file");
-    } else if (hex_digits.size() == 0) {
+    } else if (hex_digits.empty()) {
         isc_throw(OutOfRange, "template file " << file_name << " is empty");
     }
     std::vector<uint8_t> binary_stream;
@@ -1079,6 +1125,11 @@ TestControl::registerOptionFactories6() const {
                                        D6O_IA_NA,
                                        &TestControl::factoryIana6);
 
+        // D6O_IA_PD option factory.
+        LibDHCP::OptionFactoryRegister(Option::V6,
+                                       D6O_IA_PD,
+                                       &TestControl::factoryIapd6);
+
 
     }
     factories_registered = true;
@@ -1577,13 +1628,13 @@ TestControl::sendRequest6(const TestControlSocket& socket,
         }
         pkt6->addOption(opt_serverid);
     }
-    // Set IA_NA option.
-    OptionPtr opt_ia_na = advertise_pkt6->getOption(D6O_IA_NA);
-    if (!opt_ia_na) {
-        isc_throw(Unexpected, "DHCPv6 IA_NA option not found in received "
-                  "packet");
-    }
-    pkt6->addOption(opt_ia_na);
+
+    // Copy IA_NA or IA_PD option from the Advertise message to the Request
+    // message being sent to the server. This will throw exception if the
+    // option to be copied is not found. Note that this function will copy
+    // one of IA_NA or IA_PD options, depending on the lease-type value
+    // specified in the command line.
+    copyIaOptions(advertise_pkt6, pkt6);
 
     // Set default packet data.
     setDefaults6(socket, pkt6);
@@ -1732,7 +1783,20 @@ TestControl::sendSolicit6(const TestControlSocket& socket,
     }
     pkt6->addOption(Option::factory(Option::V6, D6O_CLIENTID, duid));
     pkt6->addOption(Option::factory(Option::V6, D6O_ORO));
-    pkt6->addOption(Option::factory(Option::V6, D6O_IA_NA));
+
+    // Depending on the lease-type option specified, we should request
+    // IPv6 address (with IA_NA) or IPv6 prefix (IA_PD) or both.
+
+    // IA_NA
+    if (CommandOptions::instance().getLeaseType()
+        .includes(CommandOptions::LeaseType::ADDRESS)) {
+        pkt6->addOption(Option::factory(Option::V6, D6O_IA_NA));
+    }
+    // IA_PD
+    if (CommandOptions::instance().getLeaseType()
+        .includes(CommandOptions::LeaseType::PREFIX)) {
+        pkt6->addOption(Option::factory(Option::V6, D6O_IA_PD));
+    }
 
     setDefaults6(socket, pkt6);
     pkt6->pack();

+ 46 - 10
tests/tools/perfdhcp/test_control.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -55,6 +55,13 @@ static const size_t DHCPV6_SERVERID_OFFSET = 22;
 /// Default DHCPV6 IA_NA offset in the packet template.
 static const size_t DHCPV6_IA_NA_OFFSET = 40;
 
+/// @brief Exception thrown when the required option is not found in a packet.
+class OptionNotFound : public Exception {
+public:
+    OptionNotFound(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
 /// \brief Test Control class.
 ///
 /// This singleton class is used to run the performance test with
@@ -160,7 +167,7 @@ public:
         /// \param socket socket descriptor.
         TestControlSocket(const int socket);
 
-        /// \brief Destriuctor of the socket wrapper class.
+        /// \brief Destructor of the socket wrapper class.
         ///
         /// Destructor closes wrapped socket.
         ~TestControlSocket();
@@ -197,7 +204,7 @@ public:
     /// The default generator pointer.
     typedef boost::shared_ptr<NumberGenerator> NumberGeneratorPtr;
 
-    /// \brief Sequential numbers generatorc class.
+    /// \brief Sequential numbers generator class.
     class SequentialGenerator : public NumberGenerator {
     public:
         /// \brief Constructor.
@@ -213,7 +220,7 @@ public:
             }
         }
 
-        /// \brief Generate number sequentialy.
+        /// \brief Generate number sequentially.
         ///
         /// \return generated number.
         virtual uint32_t generate() {
@@ -241,7 +248,7 @@ public:
     /// brief\ Run performance test.
     ///
     /// Method runs whole performance test. Command line options must
-    /// be parsed prior to running this function. Othewise function will
+    /// be parsed prior to running this function. Otherwise function will
     /// throw exception.
     ///
     /// \throw isc::InvalidOperation if command line options are not parsed.
@@ -280,7 +287,7 @@ protected:
     /// only via \ref instance method.
     TestControl();
 
-    /// \brief Check if test exit condtitions fulfilled.
+    /// \brief Check if test exit conditions fulfilled.
     ///
     /// Method checks if the test exit conditions are fulfilled.
     /// Exit conditions are checked periodically from the
@@ -338,6 +345,17 @@ protected:
                                         uint16_t type,
                                         const dhcp::OptionBuffer& buf);
 
+    /// \brief Factory function to create IA_PD option.
+    ///
+    /// this factory function creates DHCPv6 IA_PD option instance.
+    ///
+    /// \param u universe (ignored).
+    /// \param type option-type (ignored).
+    /// \param buf option-buffer carrying sub-options.
+    static dhcp::OptionPtr factoryIapd6(dhcp::Option::Universe u,
+                                        uint16_t type,
+                                        const dhcp::OptionBuffer& buf);
+
     /// \brief Factory function to create DHCPv6 ORO option.
     ///
     /// This factory function creates DHCPv6 Option Request Option instance.
@@ -371,7 +389,7 @@ protected:
 
     /// \brief Factory function to create DHCPv4 Request List option.
     ///
-    /// This factory function creayes DHCPv4 PARAMETER_REQUEST_LIST option
+    /// This factory function creates DHCPv4 PARAMETER_REQUEST_LIST option
     /// instance with the following set of requested options:
     /// - DHO_SUBNET_MASK,
     /// - DHO_BROADCAST_ADDRESS,
@@ -527,7 +545,7 @@ protected:
     /// \brief Process received DHCPv6 packet.
     ///
     /// Method performs processing of the received DHCPv6 packet,
-    /// updates statistics and responsds to the server if required,
+    /// updates statistics and responds to the server if required,
     /// e.g. when ADVERTISE packet arrives, this function will initiate
     /// REQUEST message to the server.
     ///
@@ -578,7 +596,7 @@ protected:
     /// \brief Register option factory functions for DHCPv4 or DHCPv6.
     ///
     /// Method registers option factory functions for DHCPv4 or DHCPv6,
-    /// depending in whch mode test is currently running.
+    /// depending in which mode test is currently running.
     void registerOptionFactories() const;
 
 
@@ -612,7 +630,7 @@ protected:
     /// type and keeps them around until test finishes. Then they
     /// are printed to the user. If packet of specified type has
     /// been already stored this function perfroms no operation.
-    /// This function does not perform sainty check if packet
+    /// This function does not perform sanity check if packet
     /// pointer is valid. Make sure it is before calling it.
     ///
     /// \param pkt packet to be stored.
@@ -834,6 +852,24 @@ protected:
 
 private:
 
+    /// \brief Copies IA_NA or IA_PD option from one packet to another.
+    ///
+    /// This function checks the lease-type specified in the command line
+    /// with option -e<lease-type>. If 'address-only' value has been specified
+    /// this function expects that IA_NA option is present in the packet
+    /// encapsulated by pkt_from object. If 'prefix-only' value has been
+    /// specified, this function expects that IA_PD option is present in the
+    /// packet encapsulated by pkt_to object.
+    ///
+    /// \param [in] pkt_from A packet from which options should be copied.
+    /// \param [out] pkt_to A packet to which options should be copied.
+    ///
+    /// \throw isc::perfdhcp::OptionNotFound if a required option is not
+    /// found in the packet from which options should be copied.
+    /// \throw isc::BadValue if any of the specified pointers to packets
+    /// is NULL.
+    void copyIaOptions(const dhcp::Pkt6Ptr& pkt_from, dhcp::Pkt6Ptr& pkt_to);
+
     /// \brief Convert binary value to hex string.
     ///
     /// \todo Consider moving this function to src/lib/util.

+ 1 - 1
tests/tools/perfdhcp/tests/command_options_helper.h

@@ -115,7 +115,7 @@ private:
         // Tokenize string (space is a separator) using begin and end iteratos
         std::vector<std::string> tokens(text_iterator, text_end);
 
-        if (tokens.size() > 0) {
+        if (!tokens.empty()) {
             // Allocate array of C-strings where we will store tokens
             results = new char*[tokens.size()];
             // Store tokens in C-strings array

+ 134 - 1
tests/tools/perfdhcp/tests/command_options_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -28,6 +28,112 @@ using namespace isc;
 using namespace isc::perfdhcp;
 using namespace boost::posix_time;
 
+// Verify that default constructor sets lease type to the expected value.
+TEST(LeaseTypeTest, defaultConstructor) {
+    CommandOptions::LeaseType lease_type;
+    EXPECT_TRUE(lease_type.is(CommandOptions::LeaseType::ADDRESS));
+}
+
+// Verify that the constructor sets the lease type to the specified value.
+TEST(LeaseTypeTest, constructor) {
+    CommandOptions::LeaseType
+        lease_type1(CommandOptions::LeaseType::ADDRESS);
+    EXPECT_TRUE(lease_type1.is(CommandOptions::LeaseType::ADDRESS));
+
+    CommandOptions::LeaseType
+        lease_type2(CommandOptions::LeaseType::PREFIX);
+    EXPECT_TRUE(lease_type2.is(CommandOptions::LeaseType::PREFIX));
+}
+
+// Verify that the lease type can be modified using set() function.
+TEST(LeaseTypeTest, set) {
+    CommandOptions::LeaseType
+        lease_type(CommandOptions::LeaseType::ADDRESS);
+    EXPECT_TRUE(lease_type.is(CommandOptions::LeaseType::ADDRESS));
+
+    lease_type.set(CommandOptions::LeaseType::PREFIX);
+    EXPECT_TRUE(lease_type.is(CommandOptions::LeaseType::PREFIX));
+}
+
+// Verify that the includes() function returns true when the lease type
+// specified with the function argument is the same as the lease type
+// encapsulated by the LeaseType object on which include function is called
+// or when the lease type value encapsulated by this object is
+// ADDRESS_AND_PREFIX.
+TEST(LeaseTypeTest, includes) {
+    // Lease type: ADDRESS
+    CommandOptions::LeaseType lease_type(CommandOptions::LeaseType::ADDRESS);
+    // Lease type IS ADDRESS.
+    ASSERT_TRUE(lease_type.is(CommandOptions::LeaseType::ADDRESS));
+    // Lease type includes the ADDRESS.
+    EXPECT_TRUE(lease_type.includes(CommandOptions::LeaseType::ADDRESS));
+    // Lease type does not include PREFIX.
+    EXPECT_FALSE(lease_type.includes(CommandOptions::LeaseType::PREFIX));
+    // Lease type does not include ADDRESS_AND_PREFIX.
+    EXPECT_FALSE(
+        lease_type.includes(CommandOptions::LeaseType::ADDRESS_AND_PREFIX)
+    );
+
+    // Do the same check for PREFIX.
+    lease_type.set(CommandOptions::LeaseType::PREFIX);
+    EXPECT_FALSE(lease_type.includes(CommandOptions::LeaseType::ADDRESS));
+    EXPECT_TRUE(lease_type.includes(CommandOptions::LeaseType::PREFIX));
+    EXPECT_FALSE(
+        lease_type.includes(CommandOptions::LeaseType::ADDRESS_AND_PREFIX)
+    );
+
+    // When lease type is set to 'address-and-prefix' it means that client
+    // requests both address and prefix (IA_NA and IA_PD). Therefore, the
+    // LeaseType::includes() function should return true for both ADDRESS
+    // and PREFIX.
+    lease_type.set(CommandOptions::LeaseType::ADDRESS_AND_PREFIX);
+    EXPECT_TRUE(lease_type.includes(CommandOptions::LeaseType::ADDRESS));
+    EXPECT_TRUE(lease_type.includes(CommandOptions::LeaseType::PREFIX));
+    EXPECT_TRUE(
+        lease_type.includes(CommandOptions::LeaseType::ADDRESS_AND_PREFIX)
+    );
+
+}
+
+// Verify that the LeaseType::fromCommandLine() function parses the lease-type
+// argument specified as -e<lease-type>.
+TEST(LeaseTypeTest, fromCommandLine) {
+    CommandOptions::LeaseType
+        lease_type(CommandOptions::LeaseType::ADDRESS);
+    ASSERT_TRUE(lease_type.is(CommandOptions::LeaseType::ADDRESS));
+
+    lease_type.fromCommandLine("prefix-only");
+    ASSERT_TRUE(lease_type.is(CommandOptions::LeaseType::PREFIX));
+
+    lease_type.fromCommandLine("address-only");
+    EXPECT_TRUE(lease_type.is(CommandOptions::LeaseType::ADDRESS));
+
+    lease_type.fromCommandLine("address-and-prefix");
+    EXPECT_TRUE(lease_type.is(CommandOptions::LeaseType::ADDRESS_AND_PREFIX));
+
+    EXPECT_THROW(lease_type.fromCommandLine("bogus-parameter"),
+                 isc::InvalidParameter);
+
+}
+
+// Verify that the LeaseType::toText() function returns the textual
+// representation of the lease type specified.
+TEST(LeaseTypeTest, toText) {
+    CommandOptions::LeaseType lease_type;
+    ASSERT_TRUE(lease_type.is(CommandOptions::LeaseType::ADDRESS));
+    EXPECT_EQ("address-only (IA_NA option added to the client's request)",
+              lease_type.toText());
+
+    lease_type.set(CommandOptions::LeaseType::PREFIX);
+    EXPECT_EQ("prefix-only (IA_PD option added to the client's request)",
+              lease_type.toText());
+
+    lease_type.set(CommandOptions::LeaseType::ADDRESS_AND_PREFIX);
+    EXPECT_EQ("address-and-prefix (Both IA_NA and IA_PD options added to the"
+              " client's request)", lease_type.toText());
+
+}
+
 /// \brief Test Fixture Class
 ///
 /// This test fixture class is used to perform
@@ -60,6 +166,7 @@ protected:
         EXPECT_NO_THROW(process("perfdhcp 192.168.0.1"));
         EXPECT_EQ(4, opt.getIpVersion());
         EXPECT_EQ(CommandOptions::DORA_SARR, opt.getExchangeMode());
+        EXPECT_TRUE(opt.getLeaseType().is(CommandOptions::LeaseType::ADDRESS));
         EXPECT_EQ(0, opt.getRate());
         EXPECT_EQ(0, opt.getReportDelay());
         EXPECT_EQ(0, opt.getClientsNum());
@@ -181,6 +288,32 @@ TEST_F(CommandOptionsTest, IpVersion) {
     EXPECT_THROW(process("perfdhcp -c -l ethx all"), isc::InvalidParameter);
 }
 
+TEST_F(CommandOptionsTest, LeaseType) {
+    CommandOptions& opt = CommandOptions::instance();
+    // Check that the -e address-only works for IPv6.
+    ASSERT_NO_THROW(process("perfdhcp -6 -l etx -e address-only all"));
+    EXPECT_EQ(6, opt.getIpVersion());
+    EXPECT_EQ("etx", opt.getLocalName());
+    EXPECT_TRUE(opt.getLeaseType().is(CommandOptions::LeaseType::ADDRESS));
+    // Check that the -e address-only works for IPv4.
+    ASSERT_NO_THROW(process("perfdhcp -4 -l etx -e address-only all"));
+    EXPECT_EQ(4, opt.getIpVersion());
+    EXPECT_EQ("etx", opt.getLocalName());
+    EXPECT_TRUE(opt.getLeaseType().is(CommandOptions::LeaseType::ADDRESS));
+    // Check that the -e prefix-only works.
+    ASSERT_NO_THROW(process("perfdhcp -6 -l etx -e prefix-only all"));
+    EXPECT_EQ(6, opt.getIpVersion());
+    EXPECT_EQ("etx", opt.getLocalName());
+    EXPECT_TRUE(opt.getLeaseType().is(CommandOptions::LeaseType::PREFIX));
+    // Check that -e prefix-only must not coexist with -4 option.
+    EXPECT_THROW(process("perfdhcp -4 -l ethx -e prefix-only all"),
+                 InvalidParameter);
+    // Check that -e prefix-only must not coexist with -T options.
+    EXPECT_THROW(process("perfdhcp -6 -l ethx -e prefix-only -T file1.hex"
+                         " -T file2.hex -E 4 all"), InvalidParameter);
+
+}
+
 TEST_F(CommandOptionsTest, Rate) {
     CommandOptions& opt = CommandOptions::instance();
     EXPECT_NO_THROW(process("perfdhcp -4 -r 10 -l ethx all"));

+ 5 - 2
tests/tools/perfdhcp/tests/stats_mgr_unittest.cc

@@ -81,6 +81,10 @@ public:
     ///
     /// Method simulates sending or receiving  multiple DHCPv6 packets.
     ///
+    /// \note The xchg_type parameter is passed as non-const value to avoid
+    /// false cppcheck errors which expect enum value being passed by reference.
+    /// This error is not reported when non-const enum is passed by value.
+    ///
     /// \param stats_mgr Statistics Manager instance to be used.
     /// \param xchg_type packet exchange types.
     /// \param packet_type DHCPv6 packet type.
@@ -88,7 +92,7 @@ public:
     /// \param receive simulated packets are received (if true)
     /// or sent (if false)
     void passMultiplePackets6(const boost::shared_ptr<StatsMgr6> stats_mgr,
-                              const StatsMgr6::ExchangeType xchg_type,
+                              StatsMgr6::ExchangeType xchg_type,
                               const uint8_t packet_type,
                               const int num_packets,
                               const bool receive = false) {
@@ -347,7 +351,6 @@ TEST_F(StatsMgrTest, Delays) {
 
     // Send DISCOVER, wait 2s and receive OFFER. This will affect
     // counters in Stats Manager.
-    const unsigned int delay1 = 2;
     passDOPacketsWithDelay(stats_mgr, 2, common_transid);
 
     // Initially min delay is equal to MAX_DOUBLE. After first packets

+ 139 - 11
tests/tools/perfdhcp/tests/test_control_unittest.cc

@@ -40,7 +40,7 @@ using namespace isc::perfdhcp;
 class NakedTestControl: public TestControl {
 public:
 
-    /// \brief Incremental transaction id generaator.
+    /// \brief Incremental transaction id generator.
     ///
     /// This is incremental transaction id generator. It overrides
     /// the default transaction id generator that generates transaction
@@ -123,7 +123,7 @@ public:
     /// truncated.
     ///
     /// \param filename template file to be created.
-    /// \param buffer with binary datato be stored in file.
+    /// \param buffer with binary data to be stored in file.
     /// \param size target size of the file.
     /// \param invalid_chars inject invalid chars to the template file.
     /// \return true if file creation successful.
@@ -283,7 +283,7 @@ public:
 
     /// brief Test generation of mulitple DUIDs
     ///
-    /// Thie method checks the generation of multiple DUIDs. Number
+    /// This method checks the generation of multiple DUIDs. Number
     /// of iterations depends on the number of simulated clients.
     /// It is expected that DUID's size is 14 (consists of DUID-LLT
     /// HW type field, 4 octets of time value and MAC address). The
@@ -497,7 +497,7 @@ 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::NumberGeneratorPtr
@@ -521,7 +521,8 @@ public:
                 boost::shared_ptr<Pkt6>
                     advertise_pkt6(createAdvertisePkt6(transid));
                 // Receive ADVERTISE and send REQUEST.
-                ASSERT_NO_THROW(tc.processReceivedPacket6(sock, advertise_pkt6));
+                ASSERT_NO_THROW(tc.processReceivedPacket6(sock,
+                                                          advertise_pkt6));
                 ++transid;
             }
             if (tc.checkExitConditions()) {
@@ -646,14 +647,24 @@ private:
     /// \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);
+        boost::shared_ptr<Pkt6> advertise(new Pkt6(DHCPV6_ADVERTISE, transid));
+        // Add IA_NA if requested by the client.
+        if (CommandOptions::instance().getLeaseType()
+            .includes(CommandOptions::LeaseType::ADDRESS)) {
+            OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
+            advertise->addOption(opt_ia_na);
+        }
+        // Add IA_PD if requested by the client.
+        if (CommandOptions::instance().getLeaseType()
+            .includes(CommandOptions::LeaseType::PREFIX)) {
+            OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD);
+            advertise->addOption(opt_ia_pd);
+        }
         OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID));
         NakedTestControl tc;
         uint8_t randomized = 0;
         std::vector<uint8_t> duid(tc.generateDuid(randomized));
         OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid));
-        boost::shared_ptr<Pkt6> advertise(new Pkt6(DHCPV6_ADVERTISE, transid));
-        advertise->addOption(opt_ia_na);
         advertise->addOption(opt_serverid);
         advertise->addOption(opt_clientid);
         advertise->updateTimestamp();
@@ -737,7 +748,7 @@ TEST_F(TestControlTest, Options4) {
 
     // Get the option buffer. It should hold the combination of values
     // listed in requested_options array. However their order can be
-    // different in general so we need to search each value separatelly.
+    // different in general so we need to search each value separately.
     const OptionBuffer& requested_options_buf =
         opt_requested_options->getData();
     EXPECT_EQ(requested_options_ref.size(), requested_options_buf.size());
@@ -963,7 +974,7 @@ TEST_F(TestControlTest, Packet4Exchange) {
     EXPECT_EQ(12, iterations_performed);
 }
 
-TEST_F(TestControlTest, Packet6Exchange) {
+TEST_F(TestControlTest, Packet6ExchangeFromTemplate) {
     // Get the local loopback interface to open socket on
     // it and test packets exchanges. We don't want to fail
     // the test if interface is not available.
@@ -998,11 +1009,128 @@ TEST_F(TestControlTest, Packet6Exchange) {
     // then test should be interrupted and actual number of iterations will
     // be 6.
     const int received_num = 3;
+    // Simulate the number of Solicit-Advertise-Request-Reply (SARR) echanges.
+    // The test function generates server's responses and passes it to the
+    // TestControl class methods for processing. The number of exchanges
+    // actually performed is returned in 'iterations_performed' argument. If
+    // processing is successful, the number of performed iterations should be
+    // equal to the number of exchanges specified with the '-n' command line
+    // parameter (10 in this case). All exchanged packets carry the IA_NA option
+    // to simulate the IPv6 address acquisition and to verify that the
+    // IA_NA options returned by the server are processed correctly.
     testPkt6Exchange(iterations_num, received_num, use_templates,
                      iterations_performed);
     EXPECT_EQ(6, iterations_performed);
 }
 
+TEST_F(TestControlTest, Packet6Exchange) {
+    // Get the local loopback interface to open socket on
+    // it and test packets exchanges. We don't want to fail
+    // the test if interface is not available.
+    std::string loopback_iface(getLocalLoopback());
+    if (loopback_iface.empty()) {
+        std::cout << "Unable to find the loopback interface. Skip test."
+                  << std::endl;
+        return;
+    }
+
+    const int iterations_num = 100;
+    // Set number of iterations to 10.
+    processCmdLine("perfdhcp -l " + loopback_iface
+                   + " -e address-only"
+                   + " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
+    int iterations_performed = 0;
+    // Set number of received packets equal to number of iterations.
+    // This simulates no packet drops.
+    bool use_templates = false;
+
+    // Simulate the number of Solicit-Advertise-Request-Reply (SARR) echanges.
+    // The test function generates server's responses and passes it to the
+    // TestControl class methods for processing. The number of exchanges
+    // actually performed is returned in 'iterations_performed' argument. If
+    // processing is successful, the number of performed iterations should be
+    // equal to the number of exchanges specified with the '-n' command line
+    // parameter (10 in this case). All exchanged packets carry the IA_NA option
+    // to simulate the IPv6 address acqusition and to verify that the IA_NA
+    // options returned by the server are processed correctly.
+    testPkt6Exchange(iterations_num, iterations_num, use_templates,
+                     iterations_performed);
+    // Actual number of iterations should be 10.
+    EXPECT_EQ(10, iterations_performed);
+}
+
+TEST_F(TestControlTest, Packet6ExchangePrefixDelegation) {
+    // Get the local loopback interface to open socket on
+    // it and test packets exchanges. We don't want to fail
+    // the test if interface is not available.
+    std::string loopback_iface(getLocalLoopback());
+    if (loopback_iface.empty()) {
+        std::cout << "Unable to find the loopback interface. Skip test."
+                  << std::endl;
+        return;
+    }
+
+    const int iterations_num = 100;
+    // Set number of iterations to 10.
+    processCmdLine("perfdhcp -l " + loopback_iface
+                   + " -e prefix-only"
+                   + " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
+    int iterations_performed = 0;
+    // Set number of received packets equal to number of iterations.
+    // This simulates no packet drops.
+    bool use_templates = false;
+
+    // Simulate the number of Solicit-Advertise-Request-Reply (SARR) echanges.
+    // The test function generates server's responses and passes it to the
+    // TestControl class methods for processing. The number of exchanges
+    // actually performed is returned in 'iterations_performed' argument. If
+    // processing is successful, the number of performed iterations should be
+    // equal to the number of exchanges specified with the '-n' command line
+    // parameter (10 in this case). All exchanged packets carry the IA_PD option
+    // to simulate the Prefix Delegation and to verify that the IA_PD options
+    // returned by the server are processed correctly.
+    testPkt6Exchange(iterations_num, iterations_num, use_templates,
+                     iterations_performed);
+    // Actual number of iterations should be 10.
+    EXPECT_EQ(10, iterations_performed);
+}
+
+TEST_F(TestControlTest, Packet6ExchangeAddressAndPrefix) {
+    // Get the local loopback interface to open socket on
+    // it and test packets exchanges. We don't want to fail
+    // the test if interface is not available.
+    std::string loopback_iface(getLocalLoopback());
+    if (loopback_iface.empty()) {
+        std::cout << "Unable to find the loopback interface. Skip test."
+                  << std::endl;
+        return;
+    }
+
+    const int iterations_num = 100;
+    // Set number of iterations to 10.
+    processCmdLine("perfdhcp -l " + loopback_iface
+                   + " -e address-and-prefix"
+                   + " -6 -r 100 -n 10 -R 20 -L 10547 ::1");
+    int iterations_performed = 0;
+    // Set number of received packets equal to number of iterations.
+    // This simulates no packet drops.
+    bool use_templates = false;
+    // Simulate the number of Solicit-Advertise-Request-Reply (SARR) echanges.
+    // The test function generates server's responses and passes it to the
+    // TestControl class methods for processing. The number of exchanges
+    // actually performed is returned in 'iterations_performed' argument. If
+    // processing is successful, the number of performed iterations should be
+    // equal to the number of exchanges specified with the '-n' command line
+    // parameter (10 in this case).  All exchanged packets carry either IA_NA
+    // or IA_PD options to simulate the address and prefix acquisition with
+    // the single message and to verify that the IA_NA and IA_PD options
+    // returned by the server are processed correctly.
+    testPkt6Exchange(iterations_num, iterations_num, use_templates,
+                     iterations_performed);
+    // Actual number of iterations should be 10.
+    EXPECT_EQ(10, iterations_performed);
+}
+
 TEST_F(TestControlTest, PacketTemplates) {
     std::vector<uint8_t> template1(256);
     std::string file1("test1.hex");
@@ -1017,7 +1145,7 @@ TEST_F(TestControlTest, PacketTemplates) {
     // Size of the file is 2 times larger than binary data size.
     ASSERT_TRUE(createTemplateFile(file1, template1, template1.size() * 2));
     ASSERT_TRUE(createTemplateFile(file2, template2, template2.size() * 2));
-    CommandOptions& options = CommandOptions::instance();
+
     NakedTestControl tc;
 
     ASSERT_NO_THROW(