Browse Source

[1954] Unit tests aded for 8 command line options as well as CommandOptions class members.

Marcin Siodelski 13 years ago
parent
commit
b04764bc6d

+ 50 - 6
tests/tools/perfdhcp/command_options.cc

@@ -27,21 +27,65 @@ namespace perfdhcp {
 // Reset stored values to the defaults.
 void
 CommandOptions::reset() {
+    uint8_t mac[6] = { 0x0, 0xC, 0x1, 0x2, 0x3, 0x4 };
+    double lt[2] = { 1., 1. };
+
     ipversion_ = 4;
+    exchange_mode_ = DORR_SARR;
+    rate_ = 0;
+    report_delay_ = 0;
+    random_range_ = 0;
+    max_random_ = 0;
+    mac_prefix_.assign(mac, mac+6);
+    base_.resize(0);
+    num_request_.resize(0);
+    period_ = 0;
+    lost_time_set_ = 0;
+    lost_time_.assign(lt, lt+2);
+    max_drop_set_ = 0;
+    max_drop_.push_back(0);
+    max_drop_.push_back(0);
+    max_pdrop_.push_back(0.);
+    max_pdrop_.push_back(0.);
+    localname_.resize(0);
+    is_interface_ = false;
+    preload_ = 0;
+    aggressivity_ = 1;
+    local_port_ = 0;
+    seeded_ = false;
+    seed_ = 0;
+    broadcast_ = false;
+    rapid_commit_ = false;
+    use_first_ = false;
+    template_file_.resize(0);
+    xid_offset_.resize(0);
+    rnd_offset_.resize(0);
+    elp_offset_ = -1;
+    sid_offset_ = -1;
+    rip_offset_ = -1;
+    diags_.resize(0);
+    wrapped_.resize(0);
+    server_name_.resize(0);
 }
 
-/// Parses the command-line options and records the results.
-void
-CommandOptions::parse(int argc, char* const argv[]) {
+int
+CommandOptions::parse(int argc, char** argv, bool force_reset /*=false */) {
     int ch;
-
-    while((ch = getopt(argc, argv, ":h")) != -1) {
+    if (force_reset) {
+        reset();
+    }
+    // Reset internal variable used by getopt to index elements
+    optind = 1;
+    while((ch = 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) {
         switch (ch) {
         case 'h':
-        default:
             usage();
+            break;
+        default:
+            ;
         }
     }
+    return(0);
 }
 
 void

+ 201 - 2
tests/tools/perfdhcp/command_options.h

@@ -15,6 +15,9 @@
 #ifndef __COMMAND_OPTIONS_H
 #define __COMMAND_OPTIONS_H
 
+#include <string>
+#include <vector>
+
 namespace isc {
 namespace perfdhcp {
 
@@ -25,6 +28,10 @@ namespace perfdhcp {
 ///
 class CommandOptions {
 public:
+    enum ExchangeMode {
+        DO_SA,
+        DORR_SARR
+    };
 
     /// \brief Default Constructor
     ///
@@ -44,20 +51,212 @@ public:
     ///
     /// \param argc Argument count passed to main().
     /// \param argv Argument value array passed to main().
-    void parse(int argc, char* const argv[]);
+    /// \param force_reset Force  reset of state variables
+    /// return non-zero value if parse failed
+    int parse(int argc, char** argv, bool force_reset = false);
 
     /// \brief Returns IP version
     ///
     /// \return IP version to be used
     uint8_t getIpVersion() const { return ipversion_; }
 
+    /// \brief Returns packet exchange mode
+    ///
+    /// \return packet exchange mode
+    ExchangeMode getExchangeMode() const { return exchange_mode_; }
+
+    /// \brief Returns echange rate
+    ///
+    /// \return exchange rate per second
+    int getRate() const { return rate_; }
+
+    /// \brief Returns report delay
+    ///
+    /// \return delay between two consecutive reports
+    int getReportDelay() const { return report_delay_; }
+
+    /// \brief Returns randomization range
+    ///
+    /// \return randomization range
+    uint32_t getRandomRange() const { return random_range_; }
+
+    /// \brief Returns MAC addr prefix
+    ///
+    /// \ return MAC addr prefix to generate different clients
+    std::vector<uint8_t> getMacPrefix() const { return mac_prefix_; }
+
+    /// \brief Returns DUID prefix
+    ///
+    /// \return DUID prefix to generate different clients
+    std::vector<uint8_t> getDuidPrefix() const { return duid_prefix_; }
+
+    /// \brief Returns base values
+    ///
+    /// \return base values for xid generation
+    std::vector<std::string> getBase() const { return base_; }
+
+    /// \brief Returns number of exchanges
+    ///
+    /// \return number of exchange requests
+    std::vector<int> getNumRequests() const { return num_request_; }
+
+    /// \brief Returns test period
+    ///
+    /// \return test period
+    int getPeriod() const { return period_; }
+
+    /// \brief Returns lost time
+    ///
+    /// \return return time before request is lost
+    std::vector<double> getLostTime() const { return lost_time_; }
+
+    /// \brief Returns max drops number
+    ///
+    /// \return maximum number of lost requests
+    std::vector<int> getMaxDrop() const { return max_drop_; }
+
+    /// \brief Returns max percentage of drops
+    ///
+    /// \return maximum percentage of lost requests
+    std::vector<double> getMaxDropPercentage() const { return max_pdrop_; }
+
+    /// \brief Returns local address or interface
+    ///
+    /// \return local address or interface
+    std::string getLocalName() const { return localname_; }
+
+    /// \brief Checks if interface name is used
+    ///
+    /// \return true if interface name was specified
+    bool isInterface() const { return is_interface_; }
+
+    /// \brief Returns number of preload exchanges
+    ///
+    /// \return number of preload exchanges
+    int getPreload() const { return preload_; }
+
+    /// \brief Returns aggressivity value
+    ///
+    /// \return aggressivity value
+    int getAggressivity() const { return aggressivity_; }
+
+    /// \brief Returns local port number
+    ///
+    /// \return local port number
+    int getLocalPort() const { return local_port_; }
+
+    /// \brief Checks if seed provided
+    ///
+    /// \return true if seed was provided
+    bool isSeeded() const { return seeded_; }
+
+    /// \brief Returns radom seed
+    ///
+    /// \return random seed
+    uint32_t getSeed() const { return seed_; }
+
+    /// \brief Checks if broadcast
+    ///
+    /// \return true if broadcast handling
+    bool isBroadcast() const { return broadcast_; }
+
+    /// \brief Check if rapid commit used
+    ///
+    /// \return true if rapid commit is used
+    bool isRapidCommit() const { return rapid_commit_; }
+
+    /// \brief Check if server-ID taken from first package
+    ///
+    /// \return true if server-iD to be taken from first package
+    bool isUseFirst() const { return use_first_; }
+
+    /// \brief Returns template file names
+    ///
+    /// \return template file names
+    std::vector<std::string> getTemplateFiles() const { return template_file_; }
+
+    /// brief Returns template offsets for xid
+    ///
+    /// \return template offsets for xid
+    std::vector<int> getXidOffset() const { return xid_offset_; }
+
+    /// \brief Returns template offsets for rnd
+    ///
+    /// \return template offsets for rnd
+    std::vector<int> getRndOffset() const { return rnd_offset_; }
+
+    /// \brief Returns template offset for elapsed time
+    ///
+    /// \return template offset for elapsed time
+    int getElpOffset() const { return elp_offset_; }
+
+    /// \brief Returns template offset for server-ID
+    ///
+    /// \return template offset for server-ID
+    int getSidOffset() const { return sid_offset_; }
+
+    /// \brief Returns template offset for requested IP
+    ///
+    /// \return template offset for requested IP
+    int getRipOffset() const { return elp_offset_; }
+
+    /// \brief Returns diagnostic selectors
+    ///
+    /// \return diagnostic selector
+    std::string getDiags() const { return diags_; }
+
+    /// \brief Returns wrapped command
+    ///
+    /// \return wrapped command
+    std::string getWrapped() const { return wrapped_; }
+
+    /// \brief Returns server name
+    ///
+    /// \return server name
+    std::string getServerName() const { return server_name_; }
+
     /// \brief Print usage
     ///
     /// Prints perfdhcp usage
     void usage(void);
 
 private:
-    uint8_t ipversion_;
+    uint8_t ipversion_;                      ///< IP version
+    ExchangeMode exchange_mode_  ;           ///< Packet exchange mode (e.g. DORR/SARR)
+    int rate_;                               ///< rate in exchange per second
+    int report_delay_;                       ///< delay between two reports
+    uint32_t random_range_;                  ///< randomization range
+    uint32_t max_random_;                    ///< maximum random value
+    std::vector<uint8_t> mac_prefix_;        ///< MAC addr prefix
+    std::vector<uint8_t> duid_prefix_;       ///< DUID prefix
+    std::vector<std::string> base_;          ///< base values for xid
+    std::vector<int> num_request_;           ///< number of exchanges
+    int period_;                             ///< test period
+    int lost_time_set_;                      ///< losttime[0] was set
+    std::vector<double> lost_time_;          ///< time before a request is lost
+    int max_drop_set_;                       ///< max{p}drop[0] was set
+    std::vector<int> max_drop_;              ///< maximum number of lost requests
+    std::vector<double> max_pdrop_;          ///< maximum percentage
+    std::string localname_;                  ///< local address or interface
+    bool is_interface_;                      ///< interface vs local address
+    int preload_;                            ///< preload exchanges
+    int aggressivity_;                       ///< back to back exchanges
+    int local_port_;                         ///< local port number (host endian)
+    bool seeded_;                            ///< is a seed provided
+    uint32_t seed_;                          ///< randomization seed
+    bool broadcast_;                         ///< use broadcast
+    bool rapid_commit_;                      ///< add rapid commit option
+    bool use_first_;                         ///< where to take the server-ID
+    std::vector<std::string> template_file_; ///< template file name
+    std::vector<int> xid_offset_;            ///< template offsets (xid)*/
+    std::vector<int> rnd_offset_;            ///< template offsets (random)
+    int elp_offset_;                         ///< template offset (elapsed time)
+    int sid_offset_;                         ///< template offset (server ID)
+    int rip_offset_;                         ///< template offset (requested IP)
+    std::string diags_;                      ///< diagnostic selectors
+    std::string wrapped_;                    ///< wrapped command
+    std::string server_name_;                ///< server
+
 
 };
 

+ 154 - 3
tests/tools/perfdhcp/tests/command_options_unittest.cc

@@ -30,13 +30,164 @@ class CommandOptionsTest : public virtual ::testing::Test,
                            public virtual CommandOptions
 {
 public:
-
     /// \brief Default Constructor
     CommandOptionsTest() : CommandOptions() { }
 
+protected:
+
+    /// \brief Parse command line and cleanup
+    ///
+    /// Tokenizes command line to array of C-strings,
+    /// parses arguments and de-allocates C-strings
+    ///
+    /// \param s Command line to parse
+    /// \return non-zero if parsing failed
+    int process(const std::string& s) {
+        int argc = 0;
+        char** argv = tokenizeString(s, &argc);
+        int r = parse(argc, argv, true);
+        for(int i = 0; i < argc; ++i) {
+            free(argv[i]);
+            argv[i] = NULL;
+        }
+        free(argv);
+        return (r);
+    }
+
+    /// \brief Check initialized values
+    ///
+    /// Check if initialized values are correct
+    void checkDefaults() {
+        EXPECT_EQ(4, getIpVersion());
+        EXPECT_EQ(DORR_SARR, getExchangeMode());
+        EXPECT_EQ(0, getRate());
+        EXPECT_EQ(0, getReportDelay());
+        EXPECT_EQ(0, getRandomRange());
+        //    EXPECT_EQ(0, max_random_);
+        // TODO MAC and DUID checks
+        EXPECT_EQ(0, getBase().size());
+        EXPECT_EQ(0, getNumRequests().size());
+        EXPECT_EQ(0, getPeriod());
+        for (int i = 0; i < getLostTime().size(); ++i) {
+            EXPECT_DOUBLE_EQ(1, getLostTime()[i]);
+        }
+        ASSERT_EQ(getMaxDrop().size(), getMaxDropPercentage().size());
+        for (int i = 0; i < getMaxDrop().size(); ++i) {
+            EXPECT_EQ(0, getMaxDrop()[i]);
+            EXPECT_EQ(0, getMaxDropPercentage()[i]);
+        }
+        EXPECT_EQ("", getLocalName());
+        EXPECT_FALSE(isInterface());
+        EXPECT_EQ(0, getPreload());
+        EXPECT_EQ(1, getAggressivity());
+        EXPECT_EQ(0, getLocalPort());
+        EXPECT_FALSE(isSeeded());
+        EXPECT_EQ(0, getSeed());
+        EXPECT_FALSE(isBroadcast());
+        EXPECT_FALSE(isRapidCommit());
+        EXPECT_FALSE(isUseFirst());
+        EXPECT_EQ(0, getTemplateFiles().size());
+        EXPECT_EQ(0, getXidOffset().size());
+        EXPECT_EQ(0, getRndOffset().size());
+        EXPECT_GT(0, getElpOffset());
+        EXPECT_GT(0, getSidOffset());
+        EXPECT_GT(0, getRipOffset());
+        EXPECT_EQ("", getDiags());
+        EXPECT_EQ("", getWrapped());
+        EXPECT_EQ("", getServerName());
+    }
+
+    /// \brief Split string to array of C-strings
+    ///
+    /// \param s String to split (tokenize)
+    /// \param num Number of tokens returned
+    /// \return array of C-strings (tokens)
+    char** tokenizeString(const std::string& s, int* num) const {
+        char** results = NULL;
+        std::stringstream ss(s);
+        std::istream_iterator<std::string> sit(ss);
+        std::istream_iterator<std::string> send;
+        std::vector<std::string> tokens(sit, send);
+
+        if (tokens.size() > 0) {
+            results = static_cast<char**>(malloc(tokens.size() * sizeof(char*)));
+            if (results == NULL) {
+                throw std::bad_alloc();
+            }
+            for (int i = 0; i < tokens.size(); ++i) {
+                char* cs = static_cast<char*>(malloc(tokens[i].length() + 1));
+                strcpy(cs, tokens[i].c_str());
+                results[i] = cs;
+            }
+            if (num != NULL) {
+                *num = tokens.size();
+            }
+        }
+
+        return results;
+    }
+
 };
 
-TEST_F(CommandOptionsTest, defaults) {
-    EXPECT_EQ(4, getIpVersion());
+TEST_F(CommandOptionsTest, Defaults) {
+    process("perfdhcp");
+    checkDefaults();
+}
+
+TEST_F(CommandOptionsTest, IpVersion) {
+    process("perfdhcp -6 -l ethx");
+    EXPECT_EQ(6, getIpVersion());
+    EXPECT_EQ("ethx", getLocalName());
 }
 
+TEST_F(CommandOptionsTest, Rate) {
+    process("perfdhcp -4 -r 10 -l ethx");
+    EXPECT_EQ(10, getRate());
+    EXPECT_NE(0, process("perfdhcp -4 -r 0 -l ethx"));
+    EXPECT_NE(0, process("perfdhcp -6 -t 5 -l ethx"));
+    EXPECT_NE(0, process("perfdhcp -4 -n 150 -l ethx"));
+    EXPECT_NE(0, process("perfdhcp -6 -p 120 -l ethx"));
+    EXPECT_NE(0, process("perfdhcp -4 -D 1400 -l ethx"));
+}
+
+TEST_F(CommandOptionsTest, ReportDelay) {
+    process("perfdhcp -r 100 -t 17 -l ethx");
+    EXPECT_EQ(17, getReportDelay());
+}
+
+TEST_F(CommandOptionsTest, RandomRange) {
+    process("perfdhcp -l ethx");
+    EXPECT_EQ(200, getRandomRange());
+}
+
+TEST_F(CommandOptionsTest, Base) {
+    process("perfdhcp -6 -b MAC=10:20:30:40:50:60 -l ethx");
+    uint8_t mac[6] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60 };
+    std::vector<uint8_t> v(mac, mac+6);
+    EXPECT_EQ(v, getMacPrefix());
+    // TODO - test for DUID
+}
+
+TEST_F(CommandOptionsTest, DropTime) {
+    process("perfdhcp -l ethx -d 12");
+    ASSERT_EQ(2, getLostTime().size());
+    EXPECT_DOUBLE_EQ(12, getLostTime()[0]);
+    EXPECT_DOUBLE_EQ(1, getLostTime()[1]);
+
+    process("perfdhcp -l ethx -d 2 -d 4.7");
+    ASSERT_EQ(2, getLostTime().size());
+    EXPECT_DOUBLE_EQ(2, getLostTime()[0]);
+    EXPECT_DOUBLE_EQ(4.7, getLostTime()[1]);
+}
+
+TEST_F(CommandOptionsTest, TimeOffset) {
+    process("perfdhcp -l ethx -E 4");
+    ASSERT_EQ(5, getElpOffset());
+    ASSERT_NE(0, process("perfdhcp -l ethx -E -3"));
+    ASSERT_NE(0, process("perfdhcp -l ethx -E 3 -i"));
+}
+
+TEST_F(CommandOptionsTest, ExchangeMode) {
+    process("perfdhcp -i -l ethx");
+    ASSERT_EQ(DO_SA, getExchangeMode());
+}