1 // Copyright (C) 2012-2021 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
9 #include <cstddef>
10 #include <fstream>
11 #include <gtest/gtest.h>
12 #include <stdint.h>
13 #include <string>
14 #include <boost/date_time/posix_time/posix_time.hpp>
15 
16 #include <dhcp/iface_mgr.h>
17 #include <exceptions/exceptions.h>
18 
19 #include "command_options_helper.h"
20 
21 using namespace std;
22 using namespace isc;
23 using namespace isc::perfdhcp;
24 using namespace boost::posix_time;
25 
26 // Verify that default constructor sets lease type to the expected value.
TEST(LeaseTypeTest,defaultConstructor)27 TEST(LeaseTypeTest, defaultConstructor) {
28     CommandOptions::LeaseType lease_type;
29     EXPECT_TRUE(lease_type.is(CommandOptions::LeaseType::ADDRESS));
30 }
31 
32 // Verify that the constructor sets the lease type to the specified value.
TEST(LeaseTypeTest,constructor)33 TEST(LeaseTypeTest, constructor) {
34     CommandOptions::LeaseType
35         lease_type1(CommandOptions::LeaseType::ADDRESS);
36     EXPECT_TRUE(lease_type1.is(CommandOptions::LeaseType::ADDRESS));
37 
38     CommandOptions::LeaseType
39         lease_type2(CommandOptions::LeaseType::PREFIX);
40     EXPECT_TRUE(lease_type2.is(CommandOptions::LeaseType::PREFIX));
41 }
42 
43 // Verify that the lease type can be modified using set() function.
TEST(LeaseTypeTest,set)44 TEST(LeaseTypeTest, set) {
45     CommandOptions::LeaseType
46         lease_type(CommandOptions::LeaseType::ADDRESS);
47     EXPECT_TRUE(lease_type.is(CommandOptions::LeaseType::ADDRESS));
48 
49     lease_type.set(CommandOptions::LeaseType::PREFIX);
50     EXPECT_TRUE(lease_type.is(CommandOptions::LeaseType::PREFIX));
51 }
52 
53 // Verify that the includes() function returns true when the lease type
54 // specified with the function argument is the same as the lease type
55 // encapsulated by the LeaseType object on which include function is called
56 // or when the lease type value encapsulated by this object is
57 // ADDRESS_AND_PREFIX.
TEST(LeaseTypeTest,includes)58 TEST(LeaseTypeTest, includes) {
59     // Lease type: ADDRESS
60     CommandOptions::LeaseType lease_type(CommandOptions::LeaseType::ADDRESS);
61     // Lease type IS ADDRESS.
62     ASSERT_TRUE(lease_type.is(CommandOptions::LeaseType::ADDRESS));
63     // Lease type includes the ADDRESS.
64     EXPECT_TRUE(lease_type.includes(CommandOptions::LeaseType::ADDRESS));
65     // Lease type does not include PREFIX.
66     EXPECT_FALSE(lease_type.includes(CommandOptions::LeaseType::PREFIX));
67     // Lease type does not include ADDRESS_AND_PREFIX.
68     EXPECT_FALSE(
69         lease_type.includes(CommandOptions::LeaseType::ADDRESS_AND_PREFIX)
70     );
71 
72     // Do the same check for PREFIX.
73     lease_type.set(CommandOptions::LeaseType::PREFIX);
74     EXPECT_FALSE(lease_type.includes(CommandOptions::LeaseType::ADDRESS));
75     EXPECT_TRUE(lease_type.includes(CommandOptions::LeaseType::PREFIX));
76     EXPECT_FALSE(
77         lease_type.includes(CommandOptions::LeaseType::ADDRESS_AND_PREFIX)
78     );
79 
80     // When lease type is set to 'address-and-prefix' it means that client
81     // requests both address and prefix (IA_NA and IA_PD). Therefore, the
82     // LeaseType::includes() function should return true for both ADDRESS
83     // and PREFIX.
84     lease_type.set(CommandOptions::LeaseType::ADDRESS_AND_PREFIX);
85     EXPECT_TRUE(lease_type.includes(CommandOptions::LeaseType::ADDRESS));
86     EXPECT_TRUE(lease_type.includes(CommandOptions::LeaseType::PREFIX));
87     EXPECT_TRUE(
88         lease_type.includes(CommandOptions::LeaseType::ADDRESS_AND_PREFIX)
89     );
90 
91 }
92 
93 // Verify that the LeaseType::fromCommandLine() function parses the lease-type
94 // argument specified as -e<lease-type>.
TEST(LeaseTypeTest,fromCommandLine)95 TEST(LeaseTypeTest, fromCommandLine) {
96     CommandOptions::LeaseType
97         lease_type(CommandOptions::LeaseType::ADDRESS);
98     ASSERT_TRUE(lease_type.is(CommandOptions::LeaseType::ADDRESS));
99 
100     lease_type.fromCommandLine("prefix-only");
101     ASSERT_TRUE(lease_type.is(CommandOptions::LeaseType::PREFIX));
102 
103     lease_type.fromCommandLine("address-only");
104     EXPECT_TRUE(lease_type.is(CommandOptions::LeaseType::ADDRESS));
105 
106     lease_type.fromCommandLine("address-and-prefix");
107     EXPECT_TRUE(lease_type.is(CommandOptions::LeaseType::ADDRESS_AND_PREFIX));
108 
109     EXPECT_THROW(lease_type.fromCommandLine("bogus-parameter"),
110                  isc::InvalidParameter);
111 
112 }
113 
114 // Verify that the LeaseType::toText() function returns the textual
115 // representation of the lease type specified.
TEST(LeaseTypeTest,toText)116 TEST(LeaseTypeTest, toText) {
117     CommandOptions::LeaseType lease_type;
118     ASSERT_TRUE(lease_type.is(CommandOptions::LeaseType::ADDRESS));
119     EXPECT_EQ("address-only (IA_NA option added to the client's request)",
120               lease_type.toText());
121 
122     lease_type.set(CommandOptions::LeaseType::PREFIX);
123     EXPECT_EQ("prefix-only (IA_PD option added to the client's request)",
124               lease_type.toText());
125 
126     lease_type.set(CommandOptions::LeaseType::ADDRESS_AND_PREFIX);
127     EXPECT_EQ("address-and-prefix (Both IA_NA and IA_PD options added to the"
128               " client's request)", lease_type.toText());
129 
130 }
131 
132 /// \brief Test Fixture Class
133 ///
134 /// This test fixture class is used to perform
135 /// unit tests on perfdhcp CommandOptions class.
136 class CommandOptionsTest : public virtual ::testing::Test
137 {
138 public:
139     /// \brief Default Constructor
CommandOptionsTest()140     CommandOptionsTest() { }
141 
142 protected:
143     /// \brief Parse command line and cleanup
144     ///
145     /// The method tokenizes command line to array of C-strings,
146     /// parses arguments using CommandOptions class to set
147     /// its data members and de-allocates array of C-strings.
148     ///
149     /// \param cmdline Command line to parse.
150     /// \throws std::bad allocation if tokenization failed.
151     /// \return true if program has been run in help or version mode ('h' or 'v' flag).
process(CommandOptions & opt,const std::string & cmdline)152     bool process(CommandOptions& opt, const std::string& cmdline) {
153         return (CommandOptionsHelper::process(opt, cmdline));
154     }
155 
156     /// \brief Get full path to a file in testdata directory.
157     ///
158     /// \param filename filename being appended to absolute
159     /// path to testdata directory
160     ///
161     /// \return full path to a file in testdata directory.
getFullPath(const std::string & filename) const162     std::string getFullPath(const std::string& filename) const {
163         std::ostringstream stream;
164         stream << TEST_DATA_DIR << "/" << filename;
165         return (stream.str());
166     }
167 };
168 
TEST_F(CommandOptionsTest,Defaults)169 TEST_F(CommandOptionsTest, Defaults) {
170     CommandOptions opt;
171     EXPECT_NO_THROW(process(opt, "perfdhcp 192.168.0.1"));
172     EXPECT_EQ(4, opt.getIpVersion());
173     EXPECT_EQ(CommandOptions::DORA_SARR, opt.getExchangeMode());
174     EXPECT_TRUE(opt.getLeaseType().is(CommandOptions::LeaseType::ADDRESS));
175     EXPECT_EQ(0, opt.getRate());
176     EXPECT_EQ(0, opt.getRenewRate());
177     EXPECT_EQ(0, opt.getReleaseRate());
178     EXPECT_EQ(0, opt.getReportDelay());
179     EXPECT_EQ(0, opt.getClientsNum());
180 
181     // default mac
182     const uint8_t mac[6] = { 0x00, 0x0C, 0x01, 0x02, 0x03, 0x04 };
183     std::vector<uint8_t> v1 = opt.getMacTemplate();
184     ASSERT_EQ(6, v1.size());
185     EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac));
186 
187     // Check if DUID is initialized. The DUID-LLT is expected
188     // to start with DUID_LLT value of 1 and hardware ethernet
189     // type equal to 1 (HWETHER_TYPE).
190     const uint8_t duid_llt_and_hw[4] = { 0x0, 0x1, 0x0, 0x1 };
191     // We assume DUID-LLT length 14. This includes 4 octets of
192     // DUID_LLT value, two octets of hardware type, 4 octets
193     // of time value and 6 octets of variable link layer (MAC)
194     // address.
195     const int duid_llt_size = 14;
196     // DUID is not given from the command line but it is supposed
197     // to be initialized by the CommandOptions private method
198     // generateDuidTemplate().
199     std::vector<uint8_t> v2 = opt.getDuidTemplate();
200     ASSERT_EQ(duid_llt_size, opt.getDuidTemplate().size());
201     EXPECT_TRUE(std::equal(v2.begin(), v2.begin() + 4,
202                            duid_llt_and_hw));
203     // Check time field contents.
204     ptime now = microsec_clock::universal_time();
205     ptime duid_epoch(from_iso_string("20000101T000000"));
206     time_period period(duid_epoch, now);
207     uint32_t duration_sec = period.length().total_seconds();
208     // Read time from the template generated.
209     uint32_t duration_from_template = 0;
210     memcpy(&duration_from_template, &v2[4], 4);
211     duration_from_template = htonl(duration_from_template);
212     // In special cases, we may have overflow in time field
213     // so we give ourselves the margin of 10 seconds here.
214     // If time value has been set more then 10 seconds back
215     // it is safe to compare it with the time value generated
216     // from now.
217     if (duration_from_template > 10) {
218         EXPECT_GE(duration_sec, duration_from_template);
219     }
220 
221     EXPECT_EQ(0, opt.getBase().size());
222     EXPECT_EQ(0, opt.getNumRequests().size());
223     EXPECT_EQ(0, opt.getPeriod());
224     for (size_t i = 0; i < opt.getDropTime().size(); ++i) {
225         EXPECT_DOUBLE_EQ(1, opt.getDropTime()[i]);
226     }
227     ASSERT_EQ(opt.getMaxDrop().size(), opt.getMaxDropPercentage().size());
228     for (size_t i = 0; i < opt.getMaxDrop().size(); ++i) {
229         EXPECT_EQ(0, opt.getMaxDrop()[i]);
230         EXPECT_EQ(0, opt.getMaxDropPercentage()[i]);
231     }
232     EXPECT_EQ("", opt.getLocalName());
233     EXPECT_FALSE(opt.isInterface());
234     EXPECT_EQ(0, opt.getPreload());
235     EXPECT_EQ(0, opt.getLocalPort());
236     EXPECT_FALSE(opt.isSeeded());
237     EXPECT_EQ(0, opt.getSeed());
238     EXPECT_FALSE(opt.isBroadcast());
239     EXPECT_FALSE(opt.isRapidCommit());
240     EXPECT_FALSE(opt.isUseFirst());
241     EXPECT_FALSE(opt.getAddrUnique());
242     EXPECT_EQ(-1, opt.getIncreaseElapsedTime());
243     EXPECT_EQ(-1, opt.getWaitForElapsedTime());
244     EXPECT_EQ(0, opt.getTemplateFiles().size());
245     EXPECT_EQ(0, opt.getTransactionIdOffset().size());
246     EXPECT_EQ(0, opt.getRandomOffset().size());
247     EXPECT_GT(0, opt.getElapsedTimeOffset());
248     EXPECT_GT(0, opt.getServerIdOffset());
249     EXPECT_GT(0, opt.getRequestedIpOffset());
250     EXPECT_EQ("", opt.getDiags());
251     EXPECT_EQ("", opt.getWrapped());
252     EXPECT_EQ("192.168.0.1", opt.getServerName());
253 }
254 
TEST_F(CommandOptionsTest,HelpVersion)255 TEST_F(CommandOptionsTest, HelpVersion) {
256     // The parser is supposed to return true if 'h' or 'v' options
257     // are specified.
258     CommandOptions opt;
259     EXPECT_TRUE(process(opt, "perfdhcp -h"));
260     EXPECT_TRUE(process(opt, "perfdhcp -v"));
261     EXPECT_TRUE(process(opt, "perfdhcp -h -v"));
262     EXPECT_TRUE(process(opt, "perfdhcp -6 -l ethx -h all"));
263     EXPECT_TRUE(process(opt, "perfdhcp -l ethx -v all"));
264     // No 'h' or 'v' option specified. The false value
265     // should be returned.
266     EXPECT_FALSE(process(opt, "perfdhcp -l ethx all"));
267 }
268 
TEST_F(CommandOptionsTest,CheckAddressUniqueness)269 TEST_F(CommandOptionsTest, CheckAddressUniqueness) {
270     CommandOptions opt;
271     EXPECT_NO_THROW(process(opt, "perfdhcp -6 -u -l ethx all"));
272     EXPECT_TRUE(opt.getAddrUnique());
273 }
274 
TEST_F(CommandOptionsTest,UseFirst)275 TEST_F(CommandOptionsTest, UseFirst) {
276     CommandOptions opt;
277     EXPECT_NO_THROW(process(opt, "perfdhcp -1 -B -l ethx all"));
278     EXPECT_TRUE(opt.isUseFirst());
279 }
280 
TEST_F(CommandOptionsTest,UseCleanOutput)281 TEST_F(CommandOptionsTest, UseCleanOutput) {
282     CommandOptions opt;
283     EXPECT_NO_THROW(process(opt, "perfdhcp -6 -C, -l ethx all"));
284     EXPECT_TRUE(opt.getCleanReport());
285     EXPECT_EQ(",", opt.getCleanReportSeparator());
286 }
287 
TEST_F(CommandOptionsTest,UseRelayV6)288 TEST_F(CommandOptionsTest, UseRelayV6) {
289     CommandOptions opt;
290     EXPECT_NO_THROW(process(opt, "perfdhcp -6 -A1 -l ethx all"));
291     EXPECT_TRUE(opt.isUseRelayedV6());
292     // -4 and -A must not coexist
293     EXPECT_THROW(process(opt, "perfdhcp -4 -A1 -l ethx all"), isc::InvalidParameter);
294 }
295 
TEST_F(CommandOptionsTest,IpVersion)296 TEST_F(CommandOptionsTest, IpVersion) {
297     CommandOptions opt;
298     EXPECT_NO_THROW(process(opt, "perfdhcp -6 -l ethx -c -i all"));
299     EXPECT_EQ(6, opt.getIpVersion());
300     EXPECT_EQ("ethx", opt.getLocalName());
301     EXPECT_TRUE(opt.isRapidCommit());
302     EXPECT_FALSE(opt.isBroadcast());
303     process(opt, "perfdhcp -4 -B -l ethx all");
304     EXPECT_EQ(4, opt.getIpVersion());
305     EXPECT_TRUE(opt.isBroadcast());
306     EXPECT_FALSE(opt.isRapidCommit());
307 
308     // Negative test cases
309     // -4 and -6 must not coexist
310     EXPECT_THROW(process(opt, "perfdhcp -4 -6 -l ethx all"), isc::InvalidParameter);
311     // -6 and -B must not coexist
312     EXPECT_THROW(process(opt, "perfdhcp -6 -B -l ethx all"), isc::InvalidParameter);
313     // -c and -4 (default) must not coexist
314     EXPECT_THROW(process(opt, "perfdhcp -c -l ethx all"), isc::InvalidParameter);
315 }
316 
TEST_F(CommandOptionsTest,LeaseType)317 TEST_F(CommandOptionsTest, LeaseType) {
318     CommandOptions opt;
319     // Check that the -e address-only works for IPv6.
320     ASSERT_NO_THROW(process(opt, "perfdhcp -6 -l etx -e address-only all"));
321     EXPECT_EQ(6, opt.getIpVersion());
322     EXPECT_EQ("etx", opt.getLocalName());
323     EXPECT_TRUE(opt.getLeaseType().is(CommandOptions::LeaseType::ADDRESS));
324     // Check that the -e address-only works for IPv4.
325     ASSERT_NO_THROW(process(opt, "perfdhcp -4 -l etx -e address-only all"));
326     EXPECT_EQ(4, opt.getIpVersion());
327     EXPECT_EQ("etx", opt.getLocalName());
328     EXPECT_TRUE(opt.getLeaseType().is(CommandOptions::LeaseType::ADDRESS));
329     // Check that the -e prefix-only works.
330     ASSERT_NO_THROW(process(opt, "perfdhcp -6 -l etx -e prefix-only all"));
331     EXPECT_EQ(6, opt.getIpVersion());
332     EXPECT_EQ("etx", opt.getLocalName());
333     EXPECT_TRUE(opt.getLeaseType().is(CommandOptions::LeaseType::PREFIX));
334     // Check that -e prefix-only must not coexist with -4 option.
335     EXPECT_THROW(process(opt, "perfdhcp -4 -l ethx -e prefix-only all"),
336                  InvalidParameter);
337     // Check that -e prefix-only must not coexist with -T options.
338     EXPECT_THROW(process(opt, "perfdhcp -6 -l ethx -e prefix-only -T file1.hex"
339                          " -T file2.hex -E 4 all"), InvalidParameter);
340 
341 }
342 
TEST_F(CommandOptionsTest,Rate)343 TEST_F(CommandOptionsTest, Rate) {
344     CommandOptions opt;
345     EXPECT_NO_THROW(process(opt, "perfdhcp -4 -r 10 -l ethx all"));
346     EXPECT_EQ(10, opt.getRate());
347 
348     // Negative test cases
349     // Rate must not be 0
350     EXPECT_THROW(process(opt, "perfdhcp -4 -r 0 -l ethx all"),
351                  isc::InvalidParameter);
352 }
353 
TEST_F(CommandOptionsTest,RenewRate)354 TEST_F(CommandOptionsTest, RenewRate) {
355     CommandOptions opt;
356     // If -f is specified together with -r the command line should
357     // be accepted and the renew rate should be set.
358     EXPECT_NO_THROW(process(opt, "perfdhcp -6 -r 10 -f 10 -l ethx all"));
359     EXPECT_EQ(10, opt.getRenewRate());
360     // Check that the release rate can be set to different value than
361     // rate specified as -r<rate>. Also, swap -f and -r to make sure
362     // that order doesn't matter.
363     EXPECT_NO_THROW(process(opt, "perfdhcp -6 -f 5 -r 10 -l ethx all"));
364     EXPECT_EQ(5, opt.getRenewRate());
365     // Renew rate should also be accepted for DHCPv4 case.
366     EXPECT_NO_THROW(process(opt, "perfdhcp -4 -f 5 -r 10 -l ethx all"));
367     EXPECT_EQ(5, opt.getRenewRate());
368     // The renew rate should not be greater than the rate.
369     EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -f 11 -l ethx all"),
370                  isc::InvalidParameter);
371     // The renew-rate of 0 is invalid.
372     EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -f 0 -l ethx all"),
373                  isc::InvalidParameter);
374     // The negative renew-rate is invalid.
375     EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -f -5 -l ethx all"),
376                  isc::InvalidParameter);
377     // If -r<rate> is not specified the -f<renew-rate> should not
378     // be accepted.
379     EXPECT_THROW(process(opt, "perfdhcp -6 -f 10 -l ethx all"),
380                  isc::InvalidParameter);
381     // Renew rate should be specified.
382     EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -f -l ethx all"),
383                  isc::InvalidParameter);
384 
385     // -f and -i are mutually exclusive
386     EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -f 10 -l ethx -i all"),
387                  isc::InvalidParameter);
388 }
389 
TEST_F(CommandOptionsTest,ReleaseRate)390 TEST_F(CommandOptionsTest, ReleaseRate) {
391     CommandOptions opt;
392     // If -F is specified together with -r the command line should
393     // be accepted and the release rate should be set.
394     EXPECT_NO_THROW(process(opt, "perfdhcp -6 -r 10 -F 10 -l ethx all"));
395     EXPECT_EQ(10, opt.getReleaseRate());
396     // Check that the release rate can be set to different value than
397     // rate specified as -r<rate>. Also, swap -F and -r to make sure
398     // that order doesn't matter.
399     EXPECT_NO_THROW(process(opt, "perfdhcp -6 -F 5 -r 10 -l ethx all"));
400     EXPECT_EQ(5, opt.getReleaseRate());
401     // The release rate should not be greater than the rate.
402     EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -F 11 -l ethx all"),
403                  isc::InvalidParameter);
404     // The release-rate of 0 is invalid.
405     EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -F 0 -l ethx all"),
406                  isc::InvalidParameter);
407     // The negative release-rate is invalid.
408     EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -F -5 -l ethx all"),
409                  isc::InvalidParameter);
410     // If -r<rate> is not specified the -F<release-rate> should not
411     // be accepted.
412     EXPECT_THROW(process(opt, "perfdhcp -6 -F 10 -l ethx all"),
413                  isc::InvalidParameter);
414     // -F<release-rate> should be usable in IPv6 mode.
415     EXPECT_NO_THROW(process(opt, "perfdhcp -4 -r 10 -F 10 -l ethx all"));
416     // Release rate should be specified.
417     EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -F -l ethx all"),
418                  isc::InvalidParameter);
419     // -F and -i are mutually exclusive
420     EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -F 10 -l ethx -i all"),
421                  isc::InvalidParameter);
422 }
423 
TEST_F(CommandOptionsTest,ReleaseRenew)424 TEST_F(CommandOptionsTest, ReleaseRenew) {
425     CommandOptions opt;
426     // It should be possible to specify the -F, -f and -r options.
427     EXPECT_NO_THROW(process(opt, "perfdhcp -6 -r 10 -F 3 -f 5 -l ethx all"));
428     EXPECT_EQ(10, opt.getRate());
429     EXPECT_EQ(3, opt.getReleaseRate());
430     EXPECT_EQ(5, opt.getRenewRate());
431     // It should be possible to specify the -F and -f with the values which
432     // sum is equal to the rate specified as -r<rate>.
433     EXPECT_NO_THROW(process(opt, "perfdhcp -6 -r 8 -F 3 -f 5 -l ethx all"));
434     EXPECT_EQ(8, opt.getRate());
435     EXPECT_EQ(3, opt.getReleaseRate());
436     EXPECT_EQ(5, opt.getRenewRate());
437     // Check that the sum of the release and renew rate is not greater
438     // than the rate specified as -r<rate>.
439     EXPECT_THROW(process(opt, "perfdhcp -6 -F 6 -f 5 -r 10 -l ethx all"),
440                  isc::InvalidParameter);
441 }
442 
TEST_F(CommandOptionsTest,ReportDelay)443 TEST_F(CommandOptionsTest, ReportDelay) {
444     CommandOptions opt;
445     EXPECT_NO_THROW(process(opt, "perfdhcp -t 17 -l ethx all"));
446     EXPECT_EQ(17, opt.getReportDelay());
447 
448     // Negative test cases
449     // -t must be positive integer
450     EXPECT_THROW(process(opt, "perfdhcp -t -8 -l ethx all"),
451                  isc::InvalidParameter);
452     EXPECT_THROW(process(opt, "perfdhcp -t 0 -l ethx all"),
453                  isc::InvalidParameter);
454     EXPECT_THROW(process(opt, "perfdhcp -t s -l ethx all"),
455                  isc::InvalidParameter);
456 }
457 
TEST_F(CommandOptionsTest,ClientsNum)458 TEST_F(CommandOptionsTest, ClientsNum) {
459     CommandOptions opt;
460     EXPECT_NO_THROW(process(opt, "perfdhcp -R 200 -l ethx all"));
461     EXPECT_EQ(200, opt.getClientsNum());
462     process(opt, "perfdhcp -R 0 -l ethx all");
463     EXPECT_EQ(0, opt.getClientsNum());
464 
465     // Negative test cases
466     // Number of clients must be non-negative integer
467     EXPECT_THROW(process(opt, "perfdhcp -R -5 -l ethx all"),
468                  isc::InvalidParameter);
469     EXPECT_THROW(process(opt, "perfdhcp -R gs -l ethx all"),
470                  isc::InvalidParameter);
471 }
472 
TEST_F(CommandOptionsTest,Base)473 TEST_F(CommandOptionsTest, Base) {
474     CommandOptions opt;
475     uint8_t mac[6] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60 };
476     uint8_t duid[14] = {  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
477                           0x01, 0x01, 0x01, 0x10, 0x11, 0x1F, 0x14 };
478     // Test DUID and MAC together.
479     EXPECT_NO_THROW(process(opt, "perfdhcp -b DUID=0101010101010101010110111F14"
480                             " -b MAC=10::20::30::40::50::60"
481                             " -l 127.0.0.1 all"));
482     std::vector<uint8_t> v1 = opt.getMacTemplate();
483     std::vector<uint8_t> v2 = opt.getDuidTemplate();
484     EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac));
485     EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid));
486     // Test valid DUID.
487     EXPECT_NO_THROW(
488         process(opt, "perfdhcp -b duid=0101010101010101010110111F14 -l 127.0.0.1 all")
489     );
490 
491     ASSERT_EQ(sizeof(duid) / sizeof(uint8_t), v2.size());
492     EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid));
493     // Test mix of upper/lower case letters.
494     EXPECT_NO_THROW(process(opt, "perfdhcp -b DuiD=0101010101010101010110111F14"
495                             " -b Mac=10::20::30::40::50::60"
496                             " -l 127.0.0.1 all"));
497     v1 = opt.getMacTemplate();
498     v2 = opt.getDuidTemplate();
499     EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac));
500     EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid));
501     // Use "ether" instead of "mac".
502     EXPECT_NO_THROW(process(opt, "perfdhcp -b ether=10::20::30::40::50::60"
503                             " -l 127.0.0.1 all"));
504     v1 = opt.getMacTemplate();
505     EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac));
506     // Use "ETHER" in upper case.
507     EXPECT_NO_THROW(process(opt, "perfdhcp -b ETHER=10::20::30::40::50::60"
508                             " -l 127.0.0.1 all"));
509     v1 = opt.getMacTemplate();
510     EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac));
511     // "t" is invalid character in DUID
512     EXPECT_THROW(process(opt, "perfdhcp -6 -l ethx -b "
513                          "duid=010101010101010101t110111F14 all"),
514                  isc::InvalidParameter);
515     // "3x" is invalid value in MAC address
516     EXPECT_THROW(process(opt, "perfdhcp -b mac=10::2::3x::4::5::6 -l ethx all"),
517                  isc::InvalidParameter);
518     // Base is not specified
519     EXPECT_THROW(process(opt, "perfdhcp -b -l ethx all"),
520                  isc::InvalidParameter);
521     // Typo: should be mac= instead of mc=
522     EXPECT_THROW(process(opt, "perfdhcp -l ethx -b mc=00:01:02:03::04:05 all"),
523                  isc::InvalidParameter);
524     // Too short DUID (< 6).
525     EXPECT_THROW(process(opt, "perfdhcp -l ethx -b duid=00010203 all"),
526                  isc::InvalidParameter);
527     // Odd number of digits.
528     EXPECT_THROW(process(opt, "perfdhcp -l ethx -b duid=000102030405060 all"),
529                  isc::InvalidParameter);
530     // Too short MAC (!= 6).
531     EXPECT_THROW(process(opt, "perfdhcp -l ethx -b mac=00:01:02:04 all"),
532                  isc::InvalidParameter);
533 }
534 
TEST_F(CommandOptionsTest,DropTime)535 TEST_F(CommandOptionsTest, DropTime) {
536     CommandOptions opt;
537     EXPECT_NO_THROW(process(opt, "perfdhcp -l ethx -d 12 all"));
538     ASSERT_EQ(2, opt.getDropTime().size());
539     EXPECT_DOUBLE_EQ(12, opt.getDropTime()[0]);
540     EXPECT_DOUBLE_EQ(1, opt.getDropTime()[1]);
541 
542     EXPECT_NO_THROW(process(opt, "perfdhcp -l ethx -d 2 -d 4.7 all"));
543     ASSERT_EQ(2, opt.getDropTime().size());
544     EXPECT_DOUBLE_EQ(2, opt.getDropTime()[0]);
545     EXPECT_DOUBLE_EQ(4.7, opt.getDropTime()[1]);
546 
547     // Negative test cases
548     // Drop time must not be negative
549     EXPECT_THROW(process(opt, "perfdhcp -l ethx -d -2 -d 4.7 all"),
550                  isc::InvalidParameter);
551     EXPECT_THROW(process(opt, "perfdhcp -l ethx -d -9.1 -d 0 all"),
552                  isc::InvalidParameter);
553 }
554 
TEST_F(CommandOptionsTest,TimeOffset)555 TEST_F(CommandOptionsTest, TimeOffset) {
556     CommandOptions opt;
557     EXPECT_NO_THROW(process(opt, "perfdhcp -l ethx -T file1.x -T file2.x -E 4 all"));
558     EXPECT_EQ(4, opt.getElapsedTimeOffset());
559 
560     // Negative test cases
561     // Argument -E must be used with -T
562     EXPECT_THROW(process(opt, "perfdhcp -l ethx -E 3 -i all"),
563                  isc::InvalidParameter);
564     // Value in -E not specified
565     EXPECT_THROW(process(opt, "perfdhcp -l ethx -T file.x -E -i all"),
566                  isc::InvalidParameter);
567     // Value for -E must not be negative
568     EXPECT_THROW(process(opt, "perfdhcp -l ethx -E -3 -T file.x all"),
569                  isc::InvalidParameter);
570 }
571 
TEST_F(CommandOptionsTest,ExchangeMode)572 TEST_F(CommandOptionsTest, ExchangeMode) {
573     CommandOptions opt;
574     process(opt, "perfdhcp -l ethx -i all");
575     EXPECT_EQ(CommandOptions::DO_SA, opt.getExchangeMode());
576 
577     // Negative test cases
578     // No template file specified
579     EXPECT_THROW(process(opt, "perfdhcp -i -l ethx -X 3 all"),
580                  isc::InvalidParameter);
581     // Offsets can't be used in simple exchanges (-i)
582     EXPECT_THROW(process(opt, "perfdhcp -i -l ethx -O 2 -T file.x all"),
583                  isc::InvalidParameter);
584     EXPECT_THROW(process(opt, "perfdhcp -i -l ethx -E 3 -T file.x all"),
585                  isc::InvalidParameter);
586     EXPECT_THROW(process(opt, "perfdhcp -i -l ethx -S 1 -T file.x all"),
587                  isc::InvalidParameter);
588     EXPECT_THROW(process(opt, "perfdhcp -i -l ethx -I 2 -T file.x all"),
589                  isc::InvalidParameter);
590 }
591 
TEST_F(CommandOptionsTest,Offsets)592 TEST_F(CommandOptionsTest, Offsets) {
593     CommandOptions opt;
594     EXPECT_NO_THROW(process(opt, "perfdhcp -E5 -4 -I 2 -S3 -O 30 -X7 -l ethx "
595                             "-X3 -T file1.x -T file2.x all"));
596     EXPECT_EQ(2, opt.getRequestedIpOffset());
597     EXPECT_EQ(5, opt.getElapsedTimeOffset());
598     EXPECT_EQ(3, opt.getServerIdOffset());
599     ASSERT_EQ(2, opt.getRandomOffset().size());
600     EXPECT_EQ(30, opt.getRandomOffset()[0]);
601     EXPECT_EQ(30, opt.getRandomOffset()[1]);
602     ASSERT_EQ(2, opt.getTransactionIdOffset().size());
603     EXPECT_EQ(7, opt.getTransactionIdOffset()[0]);
604     EXPECT_EQ(3, opt.getTransactionIdOffset()[1]);
605 
606     // Negative test cases
607     // IP offset/IA_NA offset must be positive
608     EXPECT_THROW(process(opt, "perfdhcp -6 -I 0 -l ethx all"),
609                  isc::InvalidParameter);
610     EXPECT_THROW(process(opt, "perfdhcp -6 -I -4 -l ethx all"),
611                  isc::InvalidParameter);
612 
613     // \todo other negative cases
614 }
615 
TEST_F(CommandOptionsTest,LocalPort)616 TEST_F(CommandOptionsTest, LocalPort) {
617     CommandOptions opt;
618     EXPECT_NO_THROW(process(opt, "perfdhcp -l ethx -L 2000 all"));
619     EXPECT_EQ(2000, opt.getLocalPort());
620 
621     // Negative test cases
622     // Local port must be between 0..65535
623     EXPECT_THROW(process(opt, "perfdhcp -l ethx -L -2 all"),
624                  isc::InvalidParameter);
625     EXPECT_THROW(process(opt, "perfdhcp -l ethx -L all"),
626                  isc::InvalidParameter);
627     EXPECT_THROW(process(opt, "perfdhcp -l ethx -L 65540 all"),
628                  isc::InvalidParameter);
629 }
630 
TEST_F(CommandOptionsTest,Preload)631 TEST_F(CommandOptionsTest, Preload) {
632     CommandOptions opt;
633     EXPECT_NO_THROW(process(opt, "perfdhcp -1 -P 3 -l ethx all"));
634     EXPECT_EQ(3, opt.getPreload());
635 
636     // Negative test cases
637     // Number of preload packages must not be negative integer
638     EXPECT_THROW(process(opt, "perfdhcp -P -1 -l ethx all"),
639                  isc::InvalidParameter);
640     EXPECT_THROW(process(opt, "perfdhcp -P -3 -l ethx all"),
641                  isc::InvalidParameter);
642 }
643 
TEST_F(CommandOptionsTest,Seed)644 TEST_F(CommandOptionsTest, Seed) {
645     CommandOptions opt;
646     EXPECT_NO_THROW(process(opt, "perfdhcp -6 -P 2 -s 23 -l ethx all"));
647     EXPECT_EQ(23, opt.getSeed());
648     EXPECT_TRUE(opt.isSeeded());
649 
650     EXPECT_NO_THROW(process(opt, "perfdhcp -6 -P 2 -s 0 -l ethx all"));
651     EXPECT_EQ(0, opt.getSeed());
652     EXPECT_FALSE(opt.isSeeded());
653 
654     // Negative test cases
655     // Seed must be non-negative integer
656     EXPECT_THROW(process(opt, "perfdhcp -6 -P 2 -s -5 -l ethx all"),
657                  isc::InvalidParameter);
658     EXPECT_THROW(process(opt, "perfdhcp -6 -P 2 -s -l ethx all"),
659                  isc::InvalidParameter);
660 }
661 
TEST_F(CommandOptionsTest,TemplateFiles)662 TEST_F(CommandOptionsTest, TemplateFiles) {
663     CommandOptions opt;
664     EXPECT_NO_THROW(process(opt, "perfdhcp -T file1.x -l ethx all"));
665     ASSERT_EQ(1, opt.getTemplateFiles().size());
666     EXPECT_EQ("file1.x", opt.getTemplateFiles()[0]);
667 
668     EXPECT_NO_THROW(process(opt, "perfdhcp -T file1.x -s 12 -w start -T file2.x -4 -l ethx all"));
669     ASSERT_EQ(2, opt.getTemplateFiles().size());
670     EXPECT_EQ("file1.x", opt.getTemplateFiles()[0]);
671     EXPECT_EQ("file2.x", opt.getTemplateFiles()[1]);
672 
673     // Negative test cases
674     // No template file specified
675     EXPECT_THROW(process(opt, "perfdhcp -s 12 -T -l ethx all"),
676                  isc::InvalidParameter);
677     // Too many template files specified
678     EXPECT_THROW(process(opt, "perfdhcp -s 12 -l ethx -T file.x "
679                          "-T file.x -T file.x all"),
680                  isc::InvalidParameter);
681 }
682 
TEST_F(CommandOptionsTest,Wrapped)683 TEST_F(CommandOptionsTest, Wrapped) {
684     CommandOptions opt;
685     EXPECT_NO_THROW(process(opt, "perfdhcp -B -w start -i -l ethx all"));
686     EXPECT_EQ("start", opt.getWrapped());
687 
688     // Negative test cases
689     // Missing command after -w, expected start/stop
690     EXPECT_THROW(process(opt, "perfdhcp -B -i -l ethx -w all"),
691                  isc::InvalidParameter);
692 }
693 
TEST_F(CommandOptionsTest,Diagnostics)694 TEST_F(CommandOptionsTest, Diagnostics) {
695     CommandOptions opt;
696     EXPECT_NO_THROW(process(opt, "perfdhcp -l ethx -i -x asTe all"));
697     EXPECT_EQ("asTe", opt.getDiags());
698 
699     // Negative test cases
700     // No diagnostics string specified
701     EXPECT_THROW(process(opt, "perfdhcp -l ethx -i -x all"),
702                  isc::InvalidParameter);
703 }
704 
TEST_F(CommandOptionsTest,MaxDrop)705 TEST_F(CommandOptionsTest, MaxDrop) {
706     CommandOptions opt;
707     EXPECT_NO_THROW(process(opt, "perfdhcp -D 25 -l ethx all"));
708     EXPECT_EQ(25, opt.getMaxDrop()[0]);
709     EXPECT_NO_THROW(process(opt, "perfdhcp -D 25 -l ethx -D 15 all"));
710     EXPECT_EQ(25, opt.getMaxDrop()[0]);
711     EXPECT_EQ(15, opt.getMaxDrop()[1]);
712 
713     EXPECT_NO_THROW(process(opt, "perfdhcp -D 15% -l ethx all"));
714     EXPECT_EQ(15, opt.getMaxDropPercentage()[0]);
715     EXPECT_NO_THROW(process(opt, "perfdhcp -D 15% -D25% -l ethx all"));
716     EXPECT_EQ(15, opt.getMaxDropPercentage()[0]);
717     EXPECT_EQ(25, opt.getMaxDropPercentage()[1]);
718     EXPECT_NO_THROW(process(opt, "perfdhcp -D 1% -D 99% -l ethx all"));
719     EXPECT_EQ(1, opt.getMaxDropPercentage()[0]);
720     EXPECT_EQ(99, opt.getMaxDropPercentage()[1]);
721 
722     // Negative test cases
723     // Too many -D<value> options
724     EXPECT_THROW(process(opt, "perfdhcp -D 0% -D 1 -l ethx -D 3 all"),
725                  isc::InvalidParameter);
726     // Too many -D<value%> options
727     EXPECT_THROW(process(opt, "perfdhcp -D 99% -D 13% -l ethx -D 10% all"),
728                  isc::InvalidParameter);
729     // Percentage is out of bounds
730     EXPECT_THROW(process(opt, "perfdhcp -D101% -D 13% -l ethx all"),
731                  isc::InvalidParameter);
732     EXPECT_THROW(process(opt, "perfdhcp -D0% -D 13% -l ethx all"),
733                  isc::InvalidParameter);
734 }
735 
TEST_F(CommandOptionsTest,NumRequest)736 TEST_F(CommandOptionsTest, NumRequest) {
737     CommandOptions opt;
738     EXPECT_NO_THROW(process(opt, "perfdhcp -n 1000 -l ethx all"));
739     EXPECT_EQ(1000, opt.getNumRequests()[0]);
740     EXPECT_NO_THROW(process(opt, "perfdhcp -n 5 -n 500 -l ethx all"));
741     EXPECT_EQ(5, opt.getNumRequests()[0]);
742     EXPECT_EQ(500, opt.getNumRequests()[1]);
743 
744     // Negative test cases
745     // Too many -n<value> parameters, expected maximum 2
746     EXPECT_THROW(process(opt, "perfdhcp -n 1 -n 2 -l ethx -n3 all"),
747                  isc::InvalidParameter);
748     // Num request must be positive integer
749     EXPECT_THROW(process(opt, "perfdhcp -n 1 -n -22 -l ethx all"),
750                  isc::InvalidParameter);
751     EXPECT_THROW(process(opt, "perfdhcp -n 0 -l ethx all"),
752                  isc::InvalidParameter);
753 }
754 
TEST_F(CommandOptionsTest,Period)755 TEST_F(CommandOptionsTest, Period) {
756     CommandOptions opt;
757     EXPECT_NO_THROW(process(opt, "perfdhcp -p 120 -l ethx all"));
758     EXPECT_EQ(120, opt.getPeriod());
759 
760     // Negative test cases
761     // Test period must be positive integer
762     EXPECT_THROW(process(opt, "perfdhcp -p 0 -l ethx all"),
763                  isc::InvalidParameter);
764     EXPECT_THROW(process(opt, "perfdhcp -p -3 -l ethx all"),
765                  isc::InvalidParameter);
766 }
767 
TEST_F(CommandOptionsTest,Interface)768 TEST_F(CommandOptionsTest, Interface) {
769     // In order to make this test portable we need to know
770     // at least one interface name on OS where test is run.
771     // Interface Manager has ability to detect interfaces.
772     // Although we don't call initIsInterface explicitly
773     // here it is called by CommandOptions object internally
774     // so this function is covered by the test.
775     dhcp::IfaceMgr& iface_mgr = dhcp::IfaceMgr::instance();
776     const dhcp::IfaceCollection& ifaces = iface_mgr.getIfaces();
777     std::string iface_name;
778     CommandOptions opt;
779     // The local loopback interface should be available.
780     // If no interface have been found for any reason we should
781     // not fail this test.
782     if (!ifaces.empty()) {
783         // Get the name of the interface we detected.
784         iface_name = (*ifaces.begin())->getName();
785         // Use the name in the command parser.
786         ASSERT_NO_THROW(process(opt, "perfdhcp -4 -l " + iface_name + " abc"));
787         // We expect that command parser will detect that argument
788         // specified along with '-l' is the interface name.
789         EXPECT_TRUE(opt.isInterface());
790 
791         // If neither interface nor server is specified then
792         // exception is expected to be thrown.
793         EXPECT_THROW(process(opt, "perfdhcp -4"), isc::InvalidParameter);
794     }
795 }
796 
TEST_F(CommandOptionsTest,Server)797 TEST_F(CommandOptionsTest, Server) {
798     CommandOptions opt;
799     // There is at least server parameter needed. If server is not
800     // specified the local interface must be specified.
801     // The server value equal to 'all' means use broadcast.
802     ASSERT_NO_THROW(process(opt, "perfdhcp all"));
803     // Once command line is parsed we expect that server name is
804     // set to broadcast address because 'all' was specified.
805     EXPECT_TRUE(opt.isBroadcast());
806     // The broadcast address is 255.255.255.255.
807     EXPECT_EQ(DHCP_IPV4_BROADCAST_ADDRESS, opt.getServerName());
808 
809     // When all is specified for DHCPv6 mode we expect
810     // FF02::1:2 as a server name which means All DHCP
811     // servers and relay agents in local network segment
812     ASSERT_NO_THROW(process(opt, "perfdhcp -6 all"));
813     EXPECT_EQ(ALL_DHCP_RELAY_AGENTS_AND_SERVERS, opt.getServerName());
814 
815     // When server='servers' in DHCPv6 mode we expect
816     // FF05::1:3 as server name which means All DHCP
817     // servers in local network.
818     ASSERT_NO_THROW(process(opt, "perfdhcp -6 servers"));
819     EXPECT_EQ(ALL_DHCP_SERVERS, opt.getServerName());
820 
821     // If server name is neither 'all' nor 'servers'
822     // the given argument value is expected to be
823     // returned.
824     ASSERT_NO_THROW(process(opt, "perfdhcp -6 abc"));
825     EXPECT_EQ("abc", opt.getServerName());
826 }
827 
TEST_F(CommandOptionsTest,LoadMacsFromFile)828 TEST_F(CommandOptionsTest, LoadMacsFromFile) {
829     CommandOptions opt;
830 
831     std::string mac_list_full_path = getFullPath("mac-list.txt");
832     std::ostringstream cmd;
833     cmd << "perfdhcp -M " << mac_list_full_path << " abc";
834     EXPECT_NO_THROW(process(opt, cmd.str()));
835     EXPECT_EQ(mac_list_full_path, opt.getMacListFile());
836 
837     const CommandOptions::MacAddrsVector& m = opt.getMacsFromFile();
838     EXPECT_EQ(4, m.size());
839 }
840 
TEST_F(CommandOptionsTest,LoadRelay4AddrFromFile)841 TEST_F(CommandOptionsTest, LoadRelay4AddrFromFile) {
842     CommandOptions opt;
843     std::string relay_addr_list_full_path = getFullPath("relay4-list.txt");
844     std::ostringstream cmd;
845     cmd << "perfdhcp -4 -J " << relay_addr_list_full_path << " abc";
846     EXPECT_NO_THROW(process(opt, cmd.str()));
847     EXPECT_EQ(relay_addr_list_full_path, opt.getRelayAddrListFile());
848     EXPECT_TRUE(opt.checkMultiSubnet());
849     EXPECT_EQ(5, opt.getRelayAddrList().size());
850 }
851 
TEST_F(CommandOptionsTest,LoadRelay6AddrFromFile)852 TEST_F(CommandOptionsTest, LoadRelay6AddrFromFile) {
853     CommandOptions opt;
854     std::string relay_addr_list_full_path = getFullPath("relay6-list.txt");
855     std::ostringstream cmd;
856     cmd << "perfdhcp -6 -J " << relay_addr_list_full_path << " abc";
857     EXPECT_NO_THROW(process(opt, cmd.str()));
858     EXPECT_EQ(relay_addr_list_full_path, opt.getRelayAddrListFile());
859     EXPECT_TRUE(opt.checkMultiSubnet());
860     EXPECT_EQ(2, opt.getRelayAddrList().size());
861 }
862 
TEST_F(CommandOptionsTest,RelayAddr6ForVersion4)863 TEST_F(CommandOptionsTest, RelayAddr6ForVersion4) {
864     CommandOptions opt;
865     std::string relay_addr_list_full_path = getFullPath("relay6-list.txt");
866     std::ostringstream cmd;
867     cmd << "perfdhcp -4 -J " << relay_addr_list_full_path << " abc";
868     EXPECT_THROW(process(opt, cmd.str()), isc::InvalidParameter);
869     EXPECT_FALSE(opt.checkMultiSubnet());
870     EXPECT_EQ(0, opt.getRelayAddrList().size());
871 }
872 
TEST_F(CommandOptionsTest,RelayAddr4ForVersion6)873 TEST_F(CommandOptionsTest, RelayAddr4ForVersion6) {
874     CommandOptions opt;
875     std::string relay_addr_list_full_path = getFullPath("relay4-list.txt");
876     std::ostringstream cmd;
877     cmd << "perfdhcp -6 -J " << relay_addr_list_full_path << " abc";
878     EXPECT_THROW(process(opt, cmd.str()), isc::InvalidParameter);
879     EXPECT_FALSE(opt.checkMultiSubnet());
880     EXPECT_EQ(0, opt.getRelayAddrList().size());
881 }
882 
883 
TEST_F(CommandOptionsTest,LoadMacsFromFileNegativeCases)884 TEST_F(CommandOptionsTest, LoadMacsFromFileNegativeCases) {
885     CommandOptions opt;
886     // Negative test cases
887     // Too many -M parameters, expected only 1
888     EXPECT_THROW(process(opt, "perfdhcp -M foo -M foo1 all"), isc::InvalidParameter);
889     // -M option can't use with -b option
890     EXPECT_THROW(process(opt, "perfdhcp -M foo -b mac=1234 all"),
891                  isc::InvalidParameter);
892 }
893 
TEST_F(CommandOptionsTest,ElapsedTime)894 TEST_F(CommandOptionsTest, ElapsedTime) {
895     CommandOptions opt;
896     EXPECT_NO_THROW(process(opt, "perfdhcp -y 3 -Y 10 192.168.0.1"));
897 
898     EXPECT_EQ(3, opt.getIncreaseElapsedTime());
899     EXPECT_EQ(10, opt.getWaitForElapsedTime());
900 }
901