diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:15:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:15:43 +0000 |
commit | f5f56e1a1c4d9e9496fcb9d81131066a964ccd23 (patch) | |
tree | 49e44c6f87febed37efb953ab5485aa49f6481a7 /src/bin/perfdhcp/tests | |
parent | Initial commit. (diff) | |
download | isc-kea-upstream.tar.xz isc-kea-upstream.zip |
Adding upstream version 2.4.1.upstream/2.4.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
26 files changed, 8082 insertions, 0 deletions
diff --git a/src/bin/perfdhcp/tests/Makefile.am b/src/bin/perfdhcp/tests/Makefile.am new file mode 100644 index 0000000..4de5e30 --- /dev/null +++ b/src/bin/perfdhcp/tests/Makefile.am @@ -0,0 +1,58 @@ +SUBDIRS = . testdata + +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib +AM_CPPFLAGS += -I$(top_builddir)/src/bin -I$(top_srcdir)/src/bin +AM_CPPFLAGS += -I$(srcdir)/.. -I$(builddir)/.. +AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_srcdir)/testdata\" +AM_CPPFLAGS += $(BOOST_INCLUDES) +AM_CXXFLAGS = $(KEA_CXXFLAGS) + +if USE_STATIC_LINK +AM_LDFLAGS = -static +endif + +CLEANFILES = *.gcno *.gcda +# The test[1-5].hex are created by the TestControl.PacketTemplates +# unit tests and have to be removed. +CLEANFILES += test1.hex test2.hex test3.hex test4.hex test5.hex + +TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) + +TESTS = +if HAVE_GTEST +TESTS += run_unittests +run_unittests_SOURCES = run_unittests.cc +run_unittests_SOURCES += command_options_unittest.cc +run_unittests_SOURCES += perf_pkt6_unittest.cc +run_unittests_SOURCES += perf_pkt4_unittest.cc +run_unittests_SOURCES += localized_option_unittest.cc +run_unittests_SOURCES += packet_storage_unittest.cc +run_unittests_SOURCES += rate_control_unittest.cc +run_unittests_SOURCES += stats_mgr_unittest.cc +run_unittests_SOURCES += test_control_unittest.cc +run_unittests_SOURCES += receiver_unittest.cc +run_unittests_SOURCES += perf_socket_unittest.cc +run_unittests_SOURCES += basic_scen_unittest.cc +run_unittests_SOURCES += avalanche_scen_unittest.cc +run_unittests_SOURCES += command_options_helper.h +run_unittests_SOURCES += random_number_generator_unittest.cc + +run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) +run_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS) + +run_unittests_LDADD = $(top_builddir)/src/bin/perfdhcp/libperfdhcp.la +run_unittests_LDADD += $(top_builddir)/src/lib/process/libkea-process.la +run_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la +run_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la +run_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la +run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la +run_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la +run_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la +run_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la +run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la +run_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la +run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la +run_unittests_LDADD += $(CRYPTO_LIBS) $(BOOST_LIBS) $(GTEST_LDADD) +endif + +noinst_PROGRAMS = $(TESTS) diff --git a/src/bin/perfdhcp/tests/Makefile.in b/src/bin/perfdhcp/tests/Makefile.in new file mode 100644 index 0000000..43865a3 --- /dev/null +++ b/src/bin/perfdhcp/tests/Makefile.in @@ -0,0 +1,1284 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +TESTS = $(am__EXEEXT_1) +@HAVE_GTEST_TRUE@am__append_1 = run_unittests +noinst_PROGRAMS = $(am__EXEEXT_2) +subdir = src/bin/perfdhcp/tests +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ + $(top_srcdir)/m4macros/ax_cpp11.m4 \ + $(top_srcdir)/m4macros/ax_cpp20.m4 \ + $(top_srcdir)/m4macros/ax_crypto.m4 \ + $(top_srcdir)/m4macros/ax_find_library.m4 \ + $(top_srcdir)/m4macros/ax_gssapi.m4 \ + $(top_srcdir)/m4macros/ax_gtest.m4 \ + $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ + $(top_srcdir)/m4macros/ax_netconf.m4 \ + $(top_srcdir)/m4macros/libtool.m4 \ + $(top_srcdir)/m4macros/ltoptions.m4 \ + $(top_srcdir)/m4macros/ltsugar.m4 \ + $(top_srcdir)/m4macros/ltversion.m4 \ + $(top_srcdir)/m4macros/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +@HAVE_GTEST_TRUE@am__EXEEXT_1 = run_unittests$(EXEEXT) +am__EXEEXT_2 = $(am__EXEEXT_1) +PROGRAMS = $(noinst_PROGRAMS) +am__run_unittests_SOURCES_DIST = run_unittests.cc \ + command_options_unittest.cc perf_pkt6_unittest.cc \ + perf_pkt4_unittest.cc localized_option_unittest.cc \ + packet_storage_unittest.cc rate_control_unittest.cc \ + stats_mgr_unittest.cc test_control_unittest.cc \ + receiver_unittest.cc perf_socket_unittest.cc \ + basic_scen_unittest.cc avalanche_scen_unittest.cc \ + command_options_helper.h random_number_generator_unittest.cc +@HAVE_GTEST_TRUE@am_run_unittests_OBJECTS = \ +@HAVE_GTEST_TRUE@ run_unittests-run_unittests.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-command_options_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-perf_pkt6_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-perf_pkt4_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-localized_option_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-packet_storage_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-rate_control_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-stats_mgr_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-test_control_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-receiver_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-perf_socket_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-basic_scen_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-avalanche_scen_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-random_number_generator_unittest.$(OBJEXT) +run_unittests_OBJECTS = $(am_run_unittests_OBJECTS) +am__DEPENDENCIES_1 = +@HAVE_GTEST_TRUE@run_unittests_DEPENDENCIES = $(top_builddir)/src/bin/perfdhcp/libperfdhcp.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/unittests/libutil_unittests.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ +@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ +@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +run_unittests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(run_unittests_LDFLAGS) $(LDFLAGS) \ + -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = \ + ./$(DEPDIR)/run_unittests-avalanche_scen_unittest.Po \ + ./$(DEPDIR)/run_unittests-basic_scen_unittest.Po \ + ./$(DEPDIR)/run_unittests-command_options_unittest.Po \ + ./$(DEPDIR)/run_unittests-localized_option_unittest.Po \ + ./$(DEPDIR)/run_unittests-packet_storage_unittest.Po \ + ./$(DEPDIR)/run_unittests-perf_pkt4_unittest.Po \ + ./$(DEPDIR)/run_unittests-perf_pkt6_unittest.Po \ + ./$(DEPDIR)/run_unittests-perf_socket_unittest.Po \ + ./$(DEPDIR)/run_unittests-random_number_generator_unittest.Po \ + ./$(DEPDIR)/run_unittests-rate_control_unittest.Po \ + ./$(DEPDIR)/run_unittests-receiver_unittest.Po \ + ./$(DEPDIR)/run_unittests-run_unittests.Po \ + ./$(DEPDIR)/run_unittests-stats_mgr_unittest.Po \ + ./$(DEPDIR)/run_unittests-test_control_unittest.Po +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(run_unittests_SOURCES) +DIST_SOURCES = $(am__run_unittests_SOURCES_DIST) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red='[0;31m'; \ + grn='[0;32m'; \ + lgn='[1;32m'; \ + blu='[1;34m'; \ + mgn='[0;35m'; \ + brg='[1m'; \ + std='[m'; \ + fi; \ +} +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ASCIIDOC = @ASCIIDOC@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_INCLUDES = @BOOST_INCLUDES@ +BOOST_LIBS = @BOOST_LIBS@ +BOTAN_TOOL = @BOTAN_TOOL@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONTRIB_DIR = @CONTRIB_DIR@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ +CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ +CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ +CRYPTO_LIBS = @CRYPTO_LIBS@ +CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ +CRYPTO_RPATH = @CRYPTO_RPATH@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ +DISTCHECK_CONTRIB_CONFIGURE_FLAG = @DISTCHECK_CONTRIB_CONFIGURE_FLAG@ +DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ +DISTCHECK_GSSAPI_CONFIGURE_FLAG = @DISTCHECK_GSSAPI_CONFIGURE_FLAG@ +DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ +DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@ +DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG = @DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG@ +DISTCHECK_LIBYANG_CONFIGURE_FLAG = @DISTCHECK_LIBYANG_CONFIGURE_FLAG@ +DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@ +DISTCHECK_MYSQL_CONFIGURE_FLAG = @DISTCHECK_MYSQL_CONFIGURE_FLAG@ +DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@ +DISTCHECK_PGSQL_CONFIGURE_FLAG = @DISTCHECK_PGSQL_CONFIGURE_FLAG@ +DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@ +DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG = @DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG@ +DISTCHECK_SYSREPO_CONFIGURE_FLAG = @DISTCHECK_SYSREPO_CONFIGURE_FLAG@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GENHTML = @GENHTML@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GTEST_CONFIG = @GTEST_CONFIG@ +GTEST_INCLUDES = @GTEST_INCLUDES@ +GTEST_LDADD = @GTEST_LDADD@ +GTEST_LDFLAGS = @GTEST_LDFLAGS@ +GTEST_SOURCE = @GTEST_SOURCE@ +HAVE_NETCONF = @HAVE_NETCONF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KEA_CXXFLAGS = @KEA_CXXFLAGS@ +KEA_SRCID = @KEA_SRCID@ +KRB5_CONFIG = @KRB5_CONFIG@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBYANGCPP_CPPFLAGS = @LIBYANGCPP_CPPFLAGS@ +LIBYANGCPP_INCLUDEDIR = @LIBYANGCPP_INCLUDEDIR@ +LIBYANGCPP_LIBS = @LIBYANGCPP_LIBS@ +LIBYANGCPP_PREFIX = @LIBYANGCPP_PREFIX@ +LIBYANGCPP_VERSION = @LIBYANGCPP_VERSION@ +LIBYANG_CPPFLAGS = @LIBYANG_CPPFLAGS@ +LIBYANG_INCLUDEDIR = @LIBYANG_INCLUDEDIR@ +LIBYANG_LIBS = @LIBYANG_LIBS@ +LIBYANG_PREFIX = @LIBYANG_PREFIX@ +LIBYANG_VERSION = @LIBYANG_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ +LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LIBS = @MYSQL_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PACKAGE_VERSION_TYPE = @PACKAGE_VERSION_TYPE@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PDFLATEX = @PDFLATEX@ +PERL = @PERL@ +PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ +PGSQL_LIBS = @PGSQL_LIBS@ +PKGPYTHONDIR = @PKGPYTHONDIR@ +PKG_CONFIG = @PKG_CONFIG@ +PLANTUML = @PLANTUML@ +PREMIUM_DIR = @PREMIUM_DIR@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SEP = @SEP@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SPHINXBUILD = @SPHINXBUILD@ +SRPD_PLUGINS_PATH = @SRPD_PLUGINS_PATH@ +SR_PLUGINS_PATH = @SR_PLUGINS_PATH@ +SR_REPO_PATH = @SR_REPO_PATH@ +STRIP = @STRIP@ +SYSREPOCPP_CPPFLAGS = @SYSREPOCPP_CPPFLAGS@ +SYSREPOCPP_INCLUDEDIR = @SYSREPOCPP_INCLUDEDIR@ +SYSREPOCPP_LIBS = @SYSREPOCPP_LIBS@ +SYSREPOCPP_PREFIX = @SYSREPOCPP_PREFIX@ +SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@ +SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@ +SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@ +SYSREPO_LIBS = @SYSREPO_LIBS@ +SYSREPO_PREFIX = @SYSREPO_PREFIX@ +SYSREPO_VERSION = @SYSREPO_VERSION@ +USE_LCOV = @USE_LCOV@ +VALGRIND = @VALGRIND@ +VERSION = @VERSION@ +WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ +YACC = @YACC@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . testdata +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib \ + -I$(top_builddir)/src/bin -I$(top_srcdir)/src/bin \ + -I$(srcdir)/.. -I$(builddir)/.. \ + -DTEST_DATA_DIR=\"$(abs_srcdir)/testdata\" $(BOOST_INCLUDES) +AM_CXXFLAGS = $(KEA_CXXFLAGS) +@USE_STATIC_LINK_TRUE@AM_LDFLAGS = -static +# The test[1-5].hex are created by the TestControl.PacketTemplates +# unit tests and have to be removed. +CLEANFILES = *.gcno *.gcda test1.hex test2.hex test3.hex test4.hex \ + test5.hex +TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) +@HAVE_GTEST_TRUE@run_unittests_SOURCES = run_unittests.cc \ +@HAVE_GTEST_TRUE@ command_options_unittest.cc \ +@HAVE_GTEST_TRUE@ perf_pkt6_unittest.cc perf_pkt4_unittest.cc \ +@HAVE_GTEST_TRUE@ localized_option_unittest.cc \ +@HAVE_GTEST_TRUE@ packet_storage_unittest.cc \ +@HAVE_GTEST_TRUE@ rate_control_unittest.cc \ +@HAVE_GTEST_TRUE@ stats_mgr_unittest.cc \ +@HAVE_GTEST_TRUE@ test_control_unittest.cc receiver_unittest.cc \ +@HAVE_GTEST_TRUE@ perf_socket_unittest.cc \ +@HAVE_GTEST_TRUE@ basic_scen_unittest.cc \ +@HAVE_GTEST_TRUE@ avalanche_scen_unittest.cc \ +@HAVE_GTEST_TRUE@ command_options_helper.h \ +@HAVE_GTEST_TRUE@ random_number_generator_unittest.cc +@HAVE_GTEST_TRUE@run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) +@HAVE_GTEST_TRUE@run_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS) +@HAVE_GTEST_TRUE@run_unittests_LDADD = $(top_builddir)/src/bin/perfdhcp/libperfdhcp.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/process/libkea-process.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/hooks/libkea-hooks.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/dns/libkea-dns++.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/unittests/libutil_unittests.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \ +@HAVE_GTEST_TRUE@ $(CRYPTO_LIBS) $(BOOST_LIBS) $(GTEST_LDADD) +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/bin/perfdhcp/tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/bin/perfdhcp/tests/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +run_unittests$(EXEEXT): $(run_unittests_OBJECTS) $(run_unittests_DEPENDENCIES) $(EXTRA_run_unittests_DEPENDENCIES) + @rm -f run_unittests$(EXEEXT) + $(AM_V_CXXLD)$(run_unittests_LINK) $(run_unittests_OBJECTS) $(run_unittests_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-avalanche_scen_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-basic_scen_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-command_options_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-localized_option_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-packet_storage_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-perf_pkt4_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-perf_pkt6_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-perf_socket_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-random_number_generator_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-rate_control_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-receiver_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-run_unittests.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-stats_mgr_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-test_control_unittest.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +run_unittests-run_unittests.o: run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-run_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-run_unittests.Tpo -c -o run_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-run_unittests.Tpo $(DEPDIR)/run_unittests-run_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='run_unittests-run_unittests.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc + +run_unittests-run_unittests.obj: run_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-run_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-run_unittests.Tpo -c -o run_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-run_unittests.Tpo $(DEPDIR)/run_unittests-run_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='run_unittests-run_unittests.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi` + +run_unittests-command_options_unittest.o: command_options_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-command_options_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-command_options_unittest.Tpo -c -o run_unittests-command_options_unittest.o `test -f 'command_options_unittest.cc' || echo '$(srcdir)/'`command_options_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-command_options_unittest.Tpo $(DEPDIR)/run_unittests-command_options_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='command_options_unittest.cc' object='run_unittests-command_options_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-command_options_unittest.o `test -f 'command_options_unittest.cc' || echo '$(srcdir)/'`command_options_unittest.cc + +run_unittests-command_options_unittest.obj: command_options_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-command_options_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-command_options_unittest.Tpo -c -o run_unittests-command_options_unittest.obj `if test -f 'command_options_unittest.cc'; then $(CYGPATH_W) 'command_options_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/command_options_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-command_options_unittest.Tpo $(DEPDIR)/run_unittests-command_options_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='command_options_unittest.cc' object='run_unittests-command_options_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-command_options_unittest.obj `if test -f 'command_options_unittest.cc'; then $(CYGPATH_W) 'command_options_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/command_options_unittest.cc'; fi` + +run_unittests-perf_pkt6_unittest.o: perf_pkt6_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-perf_pkt6_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-perf_pkt6_unittest.Tpo -c -o run_unittests-perf_pkt6_unittest.o `test -f 'perf_pkt6_unittest.cc' || echo '$(srcdir)/'`perf_pkt6_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-perf_pkt6_unittest.Tpo $(DEPDIR)/run_unittests-perf_pkt6_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='perf_pkt6_unittest.cc' object='run_unittests-perf_pkt6_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-perf_pkt6_unittest.o `test -f 'perf_pkt6_unittest.cc' || echo '$(srcdir)/'`perf_pkt6_unittest.cc + +run_unittests-perf_pkt6_unittest.obj: perf_pkt6_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-perf_pkt6_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-perf_pkt6_unittest.Tpo -c -o run_unittests-perf_pkt6_unittest.obj `if test -f 'perf_pkt6_unittest.cc'; then $(CYGPATH_W) 'perf_pkt6_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/perf_pkt6_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-perf_pkt6_unittest.Tpo $(DEPDIR)/run_unittests-perf_pkt6_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='perf_pkt6_unittest.cc' object='run_unittests-perf_pkt6_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-perf_pkt6_unittest.obj `if test -f 'perf_pkt6_unittest.cc'; then $(CYGPATH_W) 'perf_pkt6_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/perf_pkt6_unittest.cc'; fi` + +run_unittests-perf_pkt4_unittest.o: perf_pkt4_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-perf_pkt4_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-perf_pkt4_unittest.Tpo -c -o run_unittests-perf_pkt4_unittest.o `test -f 'perf_pkt4_unittest.cc' || echo '$(srcdir)/'`perf_pkt4_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-perf_pkt4_unittest.Tpo $(DEPDIR)/run_unittests-perf_pkt4_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='perf_pkt4_unittest.cc' object='run_unittests-perf_pkt4_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-perf_pkt4_unittest.o `test -f 'perf_pkt4_unittest.cc' || echo '$(srcdir)/'`perf_pkt4_unittest.cc + +run_unittests-perf_pkt4_unittest.obj: perf_pkt4_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-perf_pkt4_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-perf_pkt4_unittest.Tpo -c -o run_unittests-perf_pkt4_unittest.obj `if test -f 'perf_pkt4_unittest.cc'; then $(CYGPATH_W) 'perf_pkt4_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/perf_pkt4_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-perf_pkt4_unittest.Tpo $(DEPDIR)/run_unittests-perf_pkt4_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='perf_pkt4_unittest.cc' object='run_unittests-perf_pkt4_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-perf_pkt4_unittest.obj `if test -f 'perf_pkt4_unittest.cc'; then $(CYGPATH_W) 'perf_pkt4_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/perf_pkt4_unittest.cc'; fi` + +run_unittests-localized_option_unittest.o: localized_option_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-localized_option_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-localized_option_unittest.Tpo -c -o run_unittests-localized_option_unittest.o `test -f 'localized_option_unittest.cc' || echo '$(srcdir)/'`localized_option_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-localized_option_unittest.Tpo $(DEPDIR)/run_unittests-localized_option_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='localized_option_unittest.cc' object='run_unittests-localized_option_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-localized_option_unittest.o `test -f 'localized_option_unittest.cc' || echo '$(srcdir)/'`localized_option_unittest.cc + +run_unittests-localized_option_unittest.obj: localized_option_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-localized_option_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-localized_option_unittest.Tpo -c -o run_unittests-localized_option_unittest.obj `if test -f 'localized_option_unittest.cc'; then $(CYGPATH_W) 'localized_option_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/localized_option_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-localized_option_unittest.Tpo $(DEPDIR)/run_unittests-localized_option_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='localized_option_unittest.cc' object='run_unittests-localized_option_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-localized_option_unittest.obj `if test -f 'localized_option_unittest.cc'; then $(CYGPATH_W) 'localized_option_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/localized_option_unittest.cc'; fi` + +run_unittests-packet_storage_unittest.o: packet_storage_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-packet_storage_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-packet_storage_unittest.Tpo -c -o run_unittests-packet_storage_unittest.o `test -f 'packet_storage_unittest.cc' || echo '$(srcdir)/'`packet_storage_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-packet_storage_unittest.Tpo $(DEPDIR)/run_unittests-packet_storage_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='packet_storage_unittest.cc' object='run_unittests-packet_storage_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-packet_storage_unittest.o `test -f 'packet_storage_unittest.cc' || echo '$(srcdir)/'`packet_storage_unittest.cc + +run_unittests-packet_storage_unittest.obj: packet_storage_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-packet_storage_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-packet_storage_unittest.Tpo -c -o run_unittests-packet_storage_unittest.obj `if test -f 'packet_storage_unittest.cc'; then $(CYGPATH_W) 'packet_storage_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/packet_storage_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-packet_storage_unittest.Tpo $(DEPDIR)/run_unittests-packet_storage_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='packet_storage_unittest.cc' object='run_unittests-packet_storage_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-packet_storage_unittest.obj `if test -f 'packet_storage_unittest.cc'; then $(CYGPATH_W) 'packet_storage_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/packet_storage_unittest.cc'; fi` + +run_unittests-rate_control_unittest.o: rate_control_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-rate_control_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-rate_control_unittest.Tpo -c -o run_unittests-rate_control_unittest.o `test -f 'rate_control_unittest.cc' || echo '$(srcdir)/'`rate_control_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-rate_control_unittest.Tpo $(DEPDIR)/run_unittests-rate_control_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rate_control_unittest.cc' object='run_unittests-rate_control_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-rate_control_unittest.o `test -f 'rate_control_unittest.cc' || echo '$(srcdir)/'`rate_control_unittest.cc + +run_unittests-rate_control_unittest.obj: rate_control_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-rate_control_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-rate_control_unittest.Tpo -c -o run_unittests-rate_control_unittest.obj `if test -f 'rate_control_unittest.cc'; then $(CYGPATH_W) 'rate_control_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/rate_control_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-rate_control_unittest.Tpo $(DEPDIR)/run_unittests-rate_control_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='rate_control_unittest.cc' object='run_unittests-rate_control_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-rate_control_unittest.obj `if test -f 'rate_control_unittest.cc'; then $(CYGPATH_W) 'rate_control_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/rate_control_unittest.cc'; fi` + +run_unittests-stats_mgr_unittest.o: stats_mgr_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-stats_mgr_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-stats_mgr_unittest.Tpo -c -o run_unittests-stats_mgr_unittest.o `test -f 'stats_mgr_unittest.cc' || echo '$(srcdir)/'`stats_mgr_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-stats_mgr_unittest.Tpo $(DEPDIR)/run_unittests-stats_mgr_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='stats_mgr_unittest.cc' object='run_unittests-stats_mgr_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-stats_mgr_unittest.o `test -f 'stats_mgr_unittest.cc' || echo '$(srcdir)/'`stats_mgr_unittest.cc + +run_unittests-stats_mgr_unittest.obj: stats_mgr_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-stats_mgr_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-stats_mgr_unittest.Tpo -c -o run_unittests-stats_mgr_unittest.obj `if test -f 'stats_mgr_unittest.cc'; then $(CYGPATH_W) 'stats_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/stats_mgr_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-stats_mgr_unittest.Tpo $(DEPDIR)/run_unittests-stats_mgr_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='stats_mgr_unittest.cc' object='run_unittests-stats_mgr_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-stats_mgr_unittest.obj `if test -f 'stats_mgr_unittest.cc'; then $(CYGPATH_W) 'stats_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/stats_mgr_unittest.cc'; fi` + +run_unittests-test_control_unittest.o: test_control_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-test_control_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-test_control_unittest.Tpo -c -o run_unittests-test_control_unittest.o `test -f 'test_control_unittest.cc' || echo '$(srcdir)/'`test_control_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-test_control_unittest.Tpo $(DEPDIR)/run_unittests-test_control_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test_control_unittest.cc' object='run_unittests-test_control_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-test_control_unittest.o `test -f 'test_control_unittest.cc' || echo '$(srcdir)/'`test_control_unittest.cc + +run_unittests-test_control_unittest.obj: test_control_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-test_control_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-test_control_unittest.Tpo -c -o run_unittests-test_control_unittest.obj `if test -f 'test_control_unittest.cc'; then $(CYGPATH_W) 'test_control_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/test_control_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-test_control_unittest.Tpo $(DEPDIR)/run_unittests-test_control_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='test_control_unittest.cc' object='run_unittests-test_control_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-test_control_unittest.obj `if test -f 'test_control_unittest.cc'; then $(CYGPATH_W) 'test_control_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/test_control_unittest.cc'; fi` + +run_unittests-receiver_unittest.o: receiver_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-receiver_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-receiver_unittest.Tpo -c -o run_unittests-receiver_unittest.o `test -f 'receiver_unittest.cc' || echo '$(srcdir)/'`receiver_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-receiver_unittest.Tpo $(DEPDIR)/run_unittests-receiver_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='receiver_unittest.cc' object='run_unittests-receiver_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-receiver_unittest.o `test -f 'receiver_unittest.cc' || echo '$(srcdir)/'`receiver_unittest.cc + +run_unittests-receiver_unittest.obj: receiver_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-receiver_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-receiver_unittest.Tpo -c -o run_unittests-receiver_unittest.obj `if test -f 'receiver_unittest.cc'; then $(CYGPATH_W) 'receiver_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/receiver_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-receiver_unittest.Tpo $(DEPDIR)/run_unittests-receiver_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='receiver_unittest.cc' object='run_unittests-receiver_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-receiver_unittest.obj `if test -f 'receiver_unittest.cc'; then $(CYGPATH_W) 'receiver_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/receiver_unittest.cc'; fi` + +run_unittests-perf_socket_unittest.o: perf_socket_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-perf_socket_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-perf_socket_unittest.Tpo -c -o run_unittests-perf_socket_unittest.o `test -f 'perf_socket_unittest.cc' || echo '$(srcdir)/'`perf_socket_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-perf_socket_unittest.Tpo $(DEPDIR)/run_unittests-perf_socket_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='perf_socket_unittest.cc' object='run_unittests-perf_socket_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-perf_socket_unittest.o `test -f 'perf_socket_unittest.cc' || echo '$(srcdir)/'`perf_socket_unittest.cc + +run_unittests-perf_socket_unittest.obj: perf_socket_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-perf_socket_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-perf_socket_unittest.Tpo -c -o run_unittests-perf_socket_unittest.obj `if test -f 'perf_socket_unittest.cc'; then $(CYGPATH_W) 'perf_socket_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/perf_socket_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-perf_socket_unittest.Tpo $(DEPDIR)/run_unittests-perf_socket_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='perf_socket_unittest.cc' object='run_unittests-perf_socket_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-perf_socket_unittest.obj `if test -f 'perf_socket_unittest.cc'; then $(CYGPATH_W) 'perf_socket_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/perf_socket_unittest.cc'; fi` + +run_unittests-basic_scen_unittest.o: basic_scen_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-basic_scen_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-basic_scen_unittest.Tpo -c -o run_unittests-basic_scen_unittest.o `test -f 'basic_scen_unittest.cc' || echo '$(srcdir)/'`basic_scen_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-basic_scen_unittest.Tpo $(DEPDIR)/run_unittests-basic_scen_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='basic_scen_unittest.cc' object='run_unittests-basic_scen_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-basic_scen_unittest.o `test -f 'basic_scen_unittest.cc' || echo '$(srcdir)/'`basic_scen_unittest.cc + +run_unittests-basic_scen_unittest.obj: basic_scen_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-basic_scen_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-basic_scen_unittest.Tpo -c -o run_unittests-basic_scen_unittest.obj `if test -f 'basic_scen_unittest.cc'; then $(CYGPATH_W) 'basic_scen_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/basic_scen_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-basic_scen_unittest.Tpo $(DEPDIR)/run_unittests-basic_scen_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='basic_scen_unittest.cc' object='run_unittests-basic_scen_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-basic_scen_unittest.obj `if test -f 'basic_scen_unittest.cc'; then $(CYGPATH_W) 'basic_scen_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/basic_scen_unittest.cc'; fi` + +run_unittests-avalanche_scen_unittest.o: avalanche_scen_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-avalanche_scen_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-avalanche_scen_unittest.Tpo -c -o run_unittests-avalanche_scen_unittest.o `test -f 'avalanche_scen_unittest.cc' || echo '$(srcdir)/'`avalanche_scen_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-avalanche_scen_unittest.Tpo $(DEPDIR)/run_unittests-avalanche_scen_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='avalanche_scen_unittest.cc' object='run_unittests-avalanche_scen_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-avalanche_scen_unittest.o `test -f 'avalanche_scen_unittest.cc' || echo '$(srcdir)/'`avalanche_scen_unittest.cc + +run_unittests-avalanche_scen_unittest.obj: avalanche_scen_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-avalanche_scen_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-avalanche_scen_unittest.Tpo -c -o run_unittests-avalanche_scen_unittest.obj `if test -f 'avalanche_scen_unittest.cc'; then $(CYGPATH_W) 'avalanche_scen_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/avalanche_scen_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-avalanche_scen_unittest.Tpo $(DEPDIR)/run_unittests-avalanche_scen_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='avalanche_scen_unittest.cc' object='run_unittests-avalanche_scen_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-avalanche_scen_unittest.obj `if test -f 'avalanche_scen_unittest.cc'; then $(CYGPATH_W) 'avalanche_scen_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/avalanche_scen_unittest.cc'; fi` + +run_unittests-random_number_generator_unittest.o: random_number_generator_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-random_number_generator_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-random_number_generator_unittest.Tpo -c -o run_unittests-random_number_generator_unittest.o `test -f 'random_number_generator_unittest.cc' || echo '$(srcdir)/'`random_number_generator_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-random_number_generator_unittest.Tpo $(DEPDIR)/run_unittests-random_number_generator_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='random_number_generator_unittest.cc' object='run_unittests-random_number_generator_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-random_number_generator_unittest.o `test -f 'random_number_generator_unittest.cc' || echo '$(srcdir)/'`random_number_generator_unittest.cc + +run_unittests-random_number_generator_unittest.obj: random_number_generator_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-random_number_generator_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-random_number_generator_unittest.Tpo -c -o run_unittests-random_number_generator_unittest.obj `if test -f 'random_number_generator_unittest.cc'; then $(CYGPATH_W) 'random_number_generator_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/random_number_generator_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-random_number_generator_unittest.Tpo $(DEPDIR)/run_unittests-random_number_generator_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='random_number_generator_unittest.cc' object='run_unittests-random_number_generator_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-random_number_generator_unittest.obj `if test -f 'random_number_generator_unittest.cc'; then $(CYGPATH_W) 'random_number_generator_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/random_number_generator_unittest.cc'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + fi; \ + echo "$${col}$$dashes$${std}"; \ + echo "$${col}$$banner$${std}"; \ + test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ + test -z "$$report" || echo "$${col}$$report$${std}"; \ + echo "$${col}$$dashes$${std}"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-recursive +all-am: Makefile $(PROGRAMS) +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-recursive + -rm -f ./$(DEPDIR)/run_unittests-avalanche_scen_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-basic_scen_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-command_options_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-localized_option_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-packet_storage_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-perf_pkt4_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-perf_pkt6_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-perf_socket_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-random_number_generator_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-rate_control_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-receiver_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-run_unittests.Po + -rm -f ./$(DEPDIR)/run_unittests-stats_mgr_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-test_control_unittest.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f ./$(DEPDIR)/run_unittests-avalanche_scen_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-basic_scen_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-command_options_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-localized_option_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-packet_storage_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-perf_pkt4_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-perf_pkt6_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-perf_socket_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-random_number_generator_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-rate_control_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-receiver_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-run_unittests.Po + -rm -f ./$(DEPDIR)/run_unittests-stats_mgr_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-test_control_unittest.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) check-am install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-TESTS check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/bin/perfdhcp/tests/avalanche_scen_unittest.cc b/src/bin/perfdhcp/tests/avalanche_scen_unittest.cc new file mode 100644 index 0000000..d2e119a --- /dev/null +++ b/src/bin/perfdhcp/tests/avalanche_scen_unittest.cc @@ -0,0 +1,323 @@ +// Copyright (C) 2012-2019,2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include "command_options_helper.h" +#include "../avalanche_scen.h" + +#include <asiolink/io_address.h> +#include <exceptions/exceptions.h> +#include <dhcp/dhcp4.h> +#include <dhcp/pkt4.h> +#include <dhcp/iface_mgr.h> +#include <dhcp/option6_iaaddr.h> +#include <dhcp/option6_iaprefix.h> + +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/foreach.hpp> + +#include <algorithm> +#include <cstddef> +#include <stdint.h> +#include <string> +#include <fstream> +#include <gtest/gtest.h> + +using namespace std; +using namespace boost::posix_time; +using namespace isc; +using namespace isc::dhcp; +using namespace isc::perfdhcp; + +/// \brief FakeAvalancheScenPerfSocket class that mocks PerfSocket. +/// +/// It stubs send and receive operations and collects statistics. +/// Beside that it simulates DHCP server responses for received +/// packets. +class FakeAvalancheScenPerfSocket: public BasePerfSocket { +public: + /// \brief Default constructor for FakeAvalancheScenPerfSocket. + FakeAvalancheScenPerfSocket(CommandOptions &opt) : + opt_(opt), + iface_(boost::make_shared<Iface>("fake", 0)), + sent_cnt_(0), + recv_cnt_(0), + initial_drops_cnt_(0) {}; + + CommandOptions &opt_; + + IfacePtr iface_; ///< Local fake interface. + + int sent_cnt_; ///< Counter of sent packets. + int recv_cnt_; ///< Counter of received packets. + int initial_drops_cnt_; + + /// List of pairs <msg_type, trans_id> containing responses + /// planned to send to perfdhcp. + std::list<std::tuple<uint8_t, uint32_t>> planned_responses_; + + /// \brief Simulate receiving DHCPv4 packet. + virtual dhcp::Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec) override { + (void)timeout_sec; // silence compile 'unused parameter' warning; + (void)timeout_usec; // silence compile 'unused parameter' warning; + recv_cnt_++; + + if (planned_responses_.empty()) { + return Pkt4Ptr(); + } + + // simulate initial drops + if (initial_drops_cnt_ > 0) { + planned_responses_.pop_front(); + initial_drops_cnt_--; + return(Pkt4Ptr()); + } + + // prepare received packet + auto msg = planned_responses_.front(); + planned_responses_.pop_front(); + auto msg_type = std::get<0>(msg); + Pkt4Ptr pkt(new Pkt4(msg_type, std::get<1>(msg))); + OptionPtr opt_serverid = Option::factory(Option::V4, + DHO_DHCP_SERVER_IDENTIFIER, + OptionBuffer(4, 1)); + pkt->setYiaddr(asiolink::IOAddress("127.0.0.1")); + pkt->addOption(opt_serverid); + pkt->updateTimestamp(); + return (pkt); + }; + + /// \brief Simulate receiving DHCPv6 packet. + virtual dhcp::Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec) override { + (void)timeout_sec; // silence compile 'unused parameter' warning; + (void)timeout_usec; // silence compile 'unused parameter' warning; + recv_cnt_++; + + if (planned_responses_.empty()) { + return Pkt6Ptr(); + } + + // simulate initial drops + if (initial_drops_cnt_ > 0) { + planned_responses_.pop_front(); + initial_drops_cnt_--; + return(Pkt6Ptr()); + } + + // prepare received packet + auto msg = planned_responses_.front(); + planned_responses_.pop_front(); + auto msg_type = std::get<0>(msg); + Pkt6Ptr pkt(new Pkt6(msg_type, std::get<1>(msg))); + // Add IA_NA if requested by the client. + if (opt_.getLeaseType().includes(CommandOptions::LeaseType::ADDRESS)) { + OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA); + OptionPtr iaaddr(new Option6IAAddr(D6O_IAADDR, isc::asiolink::IOAddress("fe80::abcd"), 300, 500)); + opt_ia_na->addOption(iaaddr); + pkt->addOption(opt_ia_na); + } + // Add IA_PD if requested by the client. + if (opt_.getLeaseType().includes(CommandOptions::LeaseType::PREFIX)) { + OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD); + OptionPtr iapref(new Option6IAPrefix(D6O_IAPREFIX, isc::asiolink::IOAddress("fe80::"), 64, 300, 500)); + opt_ia_pd->addOption(iapref); + pkt->addOption(opt_ia_pd); + } + OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID)); + std::vector<uint8_t> duid({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid)); + pkt->addOption(opt_serverid); + pkt->addOption(opt_clientid); + pkt->updateTimestamp(); + return (pkt); + }; + + /// \brief Simulate sending DHCPv4 packet. + virtual bool send(const dhcp::Pkt4Ptr& pkt) override { + sent_cnt_++; + pkt->updateTimestamp(); + if (pkt->getType() == DHCPDISCOVER) { + planned_responses_.push_back(std::make_tuple(DHCPOFFER, pkt->getTransid())); + } else if (pkt->getType() == DHCPREQUEST) { + planned_responses_.push_back(std::make_tuple(DHCPACK, pkt->getTransid())); + } else { + assert(0); + } + return true; + }; + + /// \brief Simulate sending DHCPv6 packet. + virtual bool send(const dhcp::Pkt6Ptr& pkt) override { + sent_cnt_++; + pkt->updateTimestamp(); + if (pkt->getType() == DHCPV6_SOLICIT) { + planned_responses_.push_back(std::make_tuple(DHCPV6_ADVERTISE, pkt->getTransid())); + } else if (pkt->getType() == DHCPV6_REQUEST) { + planned_responses_.push_back(std::make_tuple(DHCPV6_REPLY, pkt->getTransid())); + } else { + assert(0); + } + return true; + }; + + /// \brief Override getting interface. + virtual IfacePtr getIface() override { return iface_; } + + void reset() { + sent_cnt_ = 0; + recv_cnt_ = 0; + } +}; + + +/// \brief NakedAvalancheScen class. +/// +/// It exposes AvalancheScen internals for UT. +class NakedAvalancheScen: public AvalancheScen { +public: + using AvalancheScen::tc_; + using AvalancheScen::total_resent_; + + FakeAvalancheScenPerfSocket fake_sock_; + + NakedAvalancheScen(CommandOptions &opt) : AvalancheScen(opt, fake_sock_), fake_sock_(opt) {}; + +}; + + +/// \brief Test Fixture Class +/// +/// This test fixture class is used to perform +/// unit tests on perfdhcp AvalancheScenTest class. +class AvalancheScenTest : public virtual ::testing::Test +{ +public: + AvalancheScenTest() { } + + /// \brief Parse command line string with CommandOptions. + /// + /// \param cmdline command line string to be parsed. + /// \throw isc::Unexpected if unexpected error occurred. + /// \throw isc::InvalidParameter if command line is invalid. + void processCmdLine(CommandOptions &opt, const std::string& cmdline) const { + CommandOptionsHelper::process(opt, cmdline); + } + + /// \brief Get full path to a file in testdata directory. + /// + /// \param filename filename being appended to absolute + /// path to testdata directory + /// + /// \return full path to a file in testdata directory. + std::string getFullPath(const std::string& filename) const { + std::ostringstream stream; + stream << TEST_DATA_DIR << "/" << filename; + return (stream.str()); + } +}; + + +TEST_F(AvalancheScenTest, Packet4Exchange) { + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -4 -R 10 --scenario avalanche -g single 127.0.0.1"); + NakedAvalancheScen as(opt); + + as.run(); + + // Check if basic exchange of packets happened. No retransmissions expected. + EXPECT_EQ(as.total_resent_, 0); + EXPECT_EQ(as.fake_sock_.sent_cnt_, 20); // Discovery + Request + EXPECT_EQ(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::DO), 10); + EXPECT_EQ(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::DO), 10); + EXPECT_EQ(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RA), 10); + EXPECT_EQ(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RA), 10); +} + + +TEST_F(AvalancheScenTest, Packet4ExchangeOnlyDO) { + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -4 -R 10 -i --scenario avalanche -g single 127.0.0.1"); + NakedAvalancheScen as(opt); + + as.run(); + + // Check if DO exchange of packets happened only. No retransmissions expected. + EXPECT_EQ(as.total_resent_, 0); + EXPECT_EQ(as.fake_sock_.sent_cnt_, 10); // Discovery + Request + EXPECT_EQ(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::DO), 10); + EXPECT_EQ(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::DO), 10); + EXPECT_THROW(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RA), isc::BadValue); +} + + +TEST_F(AvalancheScenTest, Packet4ExchangeWithRetransmissions) { + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -4 -R 10 --scenario avalanche -g single 127.0.0.1"); + NakedAvalancheScen as(opt); + + as.fake_sock_.initial_drops_cnt_ = 2; + as.run(); + + // Check if basic exchange of packets happened. No retransmissions expected. + EXPECT_EQ(as.total_resent_, 2); + EXPECT_EQ(as.fake_sock_.sent_cnt_, 22); // Discovery + Request + EXPECT_EQ(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::DO), 10); + EXPECT_EQ(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::DO), 10); + EXPECT_EQ(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RA), 10); + EXPECT_EQ(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RA), 10); +} + + +TEST_F(AvalancheScenTest, Packet6Exchange) { + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -6 -R 10 --scenario avalanche -g single ::1"); + NakedAvalancheScen as(opt); + + as.run(); + + // Check if basic exchange of packets happened. No retransmissions expected. + EXPECT_EQ(as.total_resent_, 0); + EXPECT_GE(as.fake_sock_.sent_cnt_, 20); // Solicit + Request + EXPECT_GE(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::SA), 10); + EXPECT_GE(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::SA), 10); + EXPECT_GE(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RR), 10); + EXPECT_GE(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RR), 10); +} + + +TEST_F(AvalancheScenTest, Packet6ExchangeOnlySA) { + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -6 -R 10 -i --scenario avalanche -g single ::1"); + NakedAvalancheScen as(opt); + + as.run(); + + // Check if SA exchange of packets happened only. No retransmissions expected. + EXPECT_EQ(as.total_resent_, 0); + EXPECT_GE(as.fake_sock_.sent_cnt_, 10); // Solicit + Request + EXPECT_GE(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::SA), 10); + EXPECT_GE(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::SA), 10); + EXPECT_THROW(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RR), isc::BadValue); +} + + +TEST_F(AvalancheScenTest, Packet6ExchangeWithRetransmissions) { + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -6 -R 10 --scenario avalanche -g single ::1"); + NakedAvalancheScen as(opt); + + as.fake_sock_.initial_drops_cnt_ = 2; + as.run(); + + // Check if basic exchange of packets happened. No retransmissions expected. + EXPECT_EQ(as.total_resent_, 2); + EXPECT_EQ(as.fake_sock_.sent_cnt_, 22); // Discovery + Request + EXPECT_EQ(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::SA), 10); + EXPECT_EQ(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::SA), 10); + EXPECT_EQ(as.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RR), 10); + EXPECT_EQ(as.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RR), 10); +} diff --git a/src/bin/perfdhcp/tests/basic_scen_unittest.cc b/src/bin/perfdhcp/tests/basic_scen_unittest.cc new file mode 100644 index 0000000..5240293 --- /dev/null +++ b/src/bin/perfdhcp/tests/basic_scen_unittest.cc @@ -0,0 +1,364 @@ +// Copyright (C) 2012-2020 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include "command_options_helper.h" +#include "../basic_scen.h" + +#include <asiolink/io_address.h> +#include <exceptions/exceptions.h> +#include <dhcp/dhcp4.h> +#include <dhcp/pkt4.h> +#include <dhcp/iface_mgr.h> +#include <dhcp/option6_iaaddr.h> +#include <dhcp/option6_iaprefix.h> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/foreach.hpp> + +#include <algorithm> +#include <cstddef> +#include <stdint.h> +#include <string> +#include <fstream> +#include <mutex> +#include <gtest/gtest.h> + +using namespace std; +using namespace boost::posix_time; +using namespace isc; +using namespace isc::dhcp; +using namespace isc::perfdhcp; + +/// \brief FakeScenPerfSocket class that mocks PerfSocket. +/// +/// It stubs send and receive operations and collects statistics. +/// Beside that it simulates DHCP server responses for received +/// packets. +class FakeScenPerfSocket: public BasePerfSocket { +public: + /// \brief Default constructor for FakeScenPerfSocket. + FakeScenPerfSocket(CommandOptions &opt) : + opt_(opt), + iface_(boost::make_shared<Iface>("fake", 0)), + sent_cnt_(0), + recv_cnt_(0), + start_dropping_after_cnt_(100000) {}; + + CommandOptions &opt_; + + IfacePtr iface_; ///< Local fake interface. + + int sent_cnt_; ///< Counter of sent packets. + int recv_cnt_; ///< Counter of received packets. + + /// List of pairs <msg_type, trans_id> containing responses + /// planned to send to perfdhcp. + std::list<std::tuple<uint8_t, uint32_t>> planned_responses_; + + /// Mutex to protect internal state. + std::mutex mutex_; + + /// Limit for sent packets. After this limit not more packets + /// are sent. This simulate dropping responses. + int start_dropping_after_cnt_; + + /// \brief Simulate receiving DHCPv4 packet. + virtual dhcp::Pkt4Ptr receive4(uint32_t /*timeout_sec*/, uint32_t /*timeout_usec*/) override { + std::lock_guard<std::mutex> lock(mutex_); + recv_cnt_++; + + if (planned_responses_.empty() || sent_cnt_ >= start_dropping_after_cnt_) { + return Pkt4Ptr(); + } + auto msg = planned_responses_.front(); + planned_responses_.pop_front(); + auto msg_type = std::get<0>(msg); + Pkt4Ptr pkt(new Pkt4(msg_type, std::get<1>(msg))); + OptionPtr opt_serverid = Option::factory(Option::V4, + DHO_DHCP_SERVER_IDENTIFIER, + OptionBuffer(4, 1)); + pkt->setYiaddr(asiolink::IOAddress("127.0.0.1")); + pkt->addOption(opt_serverid); + pkt->updateTimestamp(); + return (pkt); + }; + + /// \brief Simulate receiving DHCPv6 packet. + virtual dhcp::Pkt6Ptr receive6(uint32_t /*timeout_sec*/, uint32_t /*timeout_usec*/) override { + std::lock_guard<std::mutex> lock(mutex_); + recv_cnt_++; + + if (planned_responses_.empty() || sent_cnt_ >= start_dropping_after_cnt_) { + return Pkt6Ptr(); + } + auto msg = planned_responses_.front(); + planned_responses_.pop_front(); + auto msg_type = std::get<0>(msg); + Pkt6Ptr pkt(new Pkt6(msg_type, std::get<1>(msg))); + // Add IA_NA if requested by the client. + if (opt_.getLeaseType().includes(CommandOptions::LeaseType::ADDRESS)) { + OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA); + OptionPtr iaaddr(new Option6IAAddr(D6O_IAADDR, + isc::asiolink::IOAddress("fe80::abcd"), 300, 500)); + opt_ia_na->addOption(iaaddr); + pkt->addOption(opt_ia_na); + } + // Add IA_PD if requested by the client. + if (opt_.getLeaseType().includes(CommandOptions::LeaseType::PREFIX)) { + OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD); + OptionPtr iapref(new Option6IAPrefix(D6O_IAPREFIX, + isc::asiolink::IOAddress("fe80::"), 64, 300, 500)); + opt_ia_pd->addOption(iapref); + pkt->addOption(opt_ia_pd); + } + OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID)); + std::vector<uint8_t> duid({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid)); + pkt->addOption(opt_serverid); + pkt->addOption(opt_clientid); + pkt->updateTimestamp(); + return (pkt); + }; + + /// \brief Simulate sending DHCPv4 packet. + virtual bool send(const dhcp::Pkt4Ptr& pkt) override { + std::lock_guard<std::mutex> lock(mutex_); + sent_cnt_++; + pkt->updateTimestamp(); + if (sent_cnt_ >= start_dropping_after_cnt_) { + return true; + } + if (pkt->getType() == DHCPDISCOVER) { + planned_responses_.push_back(std::make_tuple(DHCPOFFER, pkt->getTransid())); + } else if (pkt->getType() == DHCPREQUEST) { + planned_responses_.push_back(std::make_tuple(DHCPACK, pkt->getTransid())); + } else { + assert(0); + } + return true; + }; + + /// \brief Simulate sending DHCPv6 packet. + virtual bool send(const dhcp::Pkt6Ptr& pkt) override { + std::lock_guard<std::mutex> lock(mutex_); + sent_cnt_++; + pkt->updateTimestamp(); + if (sent_cnt_ >= start_dropping_after_cnt_) { + return true; + } + if (pkt->getType() == DHCPV6_SOLICIT) { + planned_responses_.push_back(std::make_tuple(DHCPV6_ADVERTISE, pkt->getTransid())); + } else if (pkt->getType() == DHCPV6_REQUEST) { + planned_responses_.push_back(std::make_tuple(DHCPV6_REPLY, pkt->getTransid())); + } else { + assert(0); + } + return true; + }; + + /// \brief Override getting interface. + virtual IfacePtr getIface() override { return iface_; } + + void reset() { + std::lock_guard<std::mutex> lock(mutex_); + sent_cnt_ = 0; + recv_cnt_ = 0; + } +}; + + +/// \brief NakedBasicScen class. +/// +/// It exposes BasicScen internals for UT. +class NakedBasicScen: public BasicScen { +public: + using BasicScen::basic_rate_control_; + using BasicScen::renew_rate_control_; + using BasicScen::release_rate_control_; + using BasicScen::tc_; + + FakeScenPerfSocket fake_sock_; + + NakedBasicScen(CommandOptions &opt) : BasicScen(opt, fake_sock_), fake_sock_(opt) {}; + +}; + + +/// \brief Test Fixture Class +/// +/// This test fixture class is used to perform +/// unit tests on perfdhcp BasicScenTest class. +class BasicScenTest : public virtual ::testing::Test +{ +public: + BasicScenTest() { } + + /// \brief Parse command line string with CommandOptions. + /// + /// \param cmdline command line string to be parsed. + /// \throw isc::Unexpected if unexpected error occurred. + /// \throw isc::InvalidParameter if command line is invalid. + void processCmdLine(CommandOptions &opt, const std::string& cmdline) const { + CommandOptionsHelper::process(opt, cmdline); + } + + /// \brief Get full path to a file in testdata directory. + /// + /// \param filename filename being appended to absolute + /// path to testdata directory + /// + /// \return full path to a file in testdata directory. + std::string getFullPath(const std::string& filename) const { + std::ostringstream stream; + stream << TEST_DATA_DIR << "/" << filename; + return (stream.str()); + } +}; + + +// This test verifies that the class members are reset to expected values. +TEST_F(BasicScenTest, initial_settings) { + CommandOptions opt; + processCmdLine(opt, "perfdhcp -6 -l ethx -r 50 -f 30 -F 10 all"); + NakedBasicScen bs(opt); + + EXPECT_EQ(50, bs.basic_rate_control_.getRate()); + EXPECT_EQ(30, bs.renew_rate_control_.getRate()); + EXPECT_EQ(10, bs.release_rate_control_.getRate()); +} + + +TEST_F(BasicScenTest, Packet4Exchange) { + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -r 100 -n 10 -g single 127.0.0.1"); + NakedBasicScen bs(opt); + bs.run(); + // The command line restricts the number of iterations to 10 + // with -n 10 parameter. + EXPECT_GE(bs.fake_sock_.sent_cnt_, 20); // Discovery + Request + EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::DO), 10); + EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::DO), 10); + EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RA), 10); + EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RA), 10); +} + +TEST_F(BasicScenTest, Address4Unique) { + // send more than 1 discover+request but with the same address + // counter of a unique addresses should be 1 + CommandOptions opt; + processCmdLine(opt, "perfdhcp -u -l fake -r 10 -n 10 -g single 127.0.0.1"); + NakedBasicScen bs(opt); + bs.run(); + EXPECT_GE(bs.fake_sock_.sent_cnt_, 5); // Discovery + Request + EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::DO), 1); + EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RA), 1); + EXPECT_GE(bs.tc_.getAllUniqueAddrReply().size(), 1); + EXPECT_GE(bs.tc_.getAllUniqueAddrAdvert().size(), 1); + EXPECT_EQ(bs.tc_.getStatsMgr().getNonUniqueAddrNum(ExchangeType::DO), 9); + EXPECT_EQ(bs.tc_.getStatsMgr().getNonUniqueAddrNum(ExchangeType::RA), 9); +} + +TEST_F(BasicScenTest, Address6Unique) { + // send more than 1 solicit+request but with the same address + // counter of a unique addresses should be 1 + CommandOptions opt; + processCmdLine(opt, "perfdhcp -6 -u -l fake -r 10 -n 10 -g single ::1"); + NakedBasicScen bs(opt); + bs.run(); + EXPECT_GE(bs.fake_sock_.sent_cnt_, 5); // Solicit + Request + EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::SA), 1); + EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RR), 1); + EXPECT_GE(bs.tc_.getAllUniqueAddrReply().size(), 1); + EXPECT_GE(bs.tc_.getAllUniqueAddrAdvert().size(), 1); + EXPECT_EQ(bs.tc_.getStatsMgr().getNonUniqueAddrNum(ExchangeType::SA), 9); + EXPECT_EQ(bs.tc_.getStatsMgr().getNonUniqueAddrNum(ExchangeType::RR), 9); +} + +TEST_F(BasicScenTest, Packet4ExchangeMaxDrop10Proc) { + CommandOptions opt; + + // With the following command line we restrict the maximum + // number of dropped packets to 10% of all. + // Use templates for this test. + processCmdLine(opt, "perfdhcp -l fake -r 100 -R 20 -n 100" + " -D 10% -L 10547 -g single" + // \todo seems to be broken as it crashes building pkt + // " -T " + getFullPath("discover-example.hex") + // + " -T " + getFullPath("request4-example.hex") + " 127.0.0.1"); + // The number iterations is restricted by the percentage of + // dropped packets (-D 10%). + NakedBasicScen bs(opt); + bs.fake_sock_.start_dropping_after_cnt_ = 10; + bs.run(); + EXPECT_GE(bs.fake_sock_.sent_cnt_, 15); // Discovery + Request + EXPECT_LE(bs.fake_sock_.sent_cnt_, 20); // Discovery + Request + + EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::DO), 1); + EXPECT_LE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::DO), 15); + + EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::DO), 1); + EXPECT_LE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::DO), 15); + + EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RA), 1); + EXPECT_LE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RA), 15); + + EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RA), 1); + EXPECT_LE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RA), 15); +} + + +TEST_F(BasicScenTest, Packet6Exchange) { + // Set number of iterations to 10. + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -6 -r 100 -n 10 -g single -R 20 -L 10547 ::1"); + // Set number of received packets equal to number of iterations. + // This simulates no packet drops. + NakedBasicScen bs(opt); + bs.run(); + EXPECT_GE(bs.fake_sock_.sent_cnt_, 20); // Solicit + Request + EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::SA), 10); + EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::SA), 10); + EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RR), 10); + EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RR), 10); +} + +TEST_F(BasicScenTest, Packet6ExchangeMaxDrop3Pkt) { + CommandOptions opt; + // The maximum number of dropped packets is 3 (because of -D 3). + processCmdLine(opt, "perfdhcp -l fake" + " -6 -r 100 -n 100 -R 20 -D 3 -L 10547" + // \todo seems to be broken as it crashes building pkt + // " -T " + getFullPath("solicit-example.hex") + // + " -T " + getFullPath("request6-example.hex") + " ::1"); + + // Simulate the number of Solicit-Advertise-Request-Reply (SARR) exchanges. + // The test function generates server's responses and passes it to the + // TestControl class methods for processing. The number of exchanges + // actually performed is controller by 'start_dropping_after_cnt_'. + // 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. + NakedBasicScen bs(opt); + bs.fake_sock_.start_dropping_after_cnt_ = 10; + bs.run(); + EXPECT_GE(bs.fake_sock_.sent_cnt_, 10); + EXPECT_LE(bs.fake_sock_.sent_cnt_, 20); + + EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::SA), 1); + EXPECT_LE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::SA), 15); + + EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::SA), 1); + EXPECT_LE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::SA), 15); + + EXPECT_GE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RR), 1); + EXPECT_LE(bs.tc_.getStatsMgr().getSentPacketsNum(ExchangeType::RR), 15); + + EXPECT_GE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RR), 1); + EXPECT_LE(bs.tc_.getStatsMgr().getRcvdPacketsNum(ExchangeType::RR), 15); +} diff --git a/src/bin/perfdhcp/tests/command_options_helper.h b/src/bin/perfdhcp/tests/command_options_helper.h new file mode 100644 index 0000000..dd8e512 --- /dev/null +++ b/src/bin/perfdhcp/tests/command_options_helper.h @@ -0,0 +1,134 @@ +// Copyright (C) 2012-2019 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef COMMAND_OPTIONS_HELPER_H +#define COMMAND_OPTIONS_HELPER_H + +#include "../command_options.h" +#include <exceptions/exceptions.h> + +#include <assert.h> +#include <iterator> +#include <cstring> +#include <string> +#include <vector> + + +namespace isc { +namespace perfdhcp { + +/// \brief Command Options Helper class. +/// +/// This helper class can be shared between unit tests that +/// need to initialize CommandOptions objects and feed it with +/// specific command line. The command line can be given as a +/// string representing program name, options and arguments. +/// The static method exposed by this class can be used to +/// tokenize this string into array of C-strings that are later +/// consumed by \ref CommandOptions::parse. The state of the +/// CommandOptions object is reset every time the process +/// function is invoked. Also, when command line parsing is +/// ended the array of C-string is freed from the memory. +class CommandOptionsHelper { +public: + + /// \brief Wrapper class for allocated argv[] array. + /// + /// This class wraps allocated char** array and ensures that memory + /// allocated for this array is freed at the end o the scope. + class ArgvPtr { + public: + /// \brief Constructor. + /// + /// \param argv array of C-strings. + /// \param number of C-strings in the array. + ArgvPtr(char** argv, int argc) : argv_(argv), argc_(argc) { } + + /// \brief Destructor. + /// + /// Deallocates wrapped array of C-strings. + ~ArgvPtr() { + if (argv_ != NULL) { + for(int i = 0; i < argc_; ++i) { + delete[] (argv_[i]); + argv_[i] = NULL; + } + delete[] (argv_); + } + } + + /// \brief Return the array of C-strings. + /// + /// \return array of C-strings. + char** getArgv() const { return (argv_); } + + /// \brief Return C-strings counter. + /// + /// \return C-strings counter. + int getArgc() const { return(argc_); } + + public: + char** argv_; ///< array of C-strings being wrapped. + int argc_; ///< number of C-strings. + }; + + /// \brief Parse command line provided as string. + /// + /// Method transforms the string representing command line + /// to the array of C-strings consumed by the + /// \ref CommandOptions::parse function and performs + /// parsing. + /// + /// \param cmdline command line provided as single string. + /// \return true if program has been run in help or version mode ('h' or 'v' flag). + static bool process(CommandOptions& opt, const std::string& cmdline) { + int argc = 0; + char** argv = tokenizeString(cmdline, argc); + ArgvPtr args(argv, argc); + opt.reset(); + return (opt.parse(args.getArgc(), args.getArgv())); + } + +private: + + /// \brief Split string to the array of C-strings. + /// + /// \param text_to_split string to be split. + /// \param [out] num number of substrings returned. + /// \param std::bad_alloc if allocation of C-strings failed. + /// \return array of C-strings created from split. + static char** tokenizeString(const std::string& text_to_split, int& num) { + char** results = NULL; + // Tokenization with std streams + std::stringstream text_stream(text_to_split); + // Iterators to be used for tokenization + std::istream_iterator<std::string> text_iterator(text_stream); + std::istream_iterator<std::string> text_end; + // Tokenize string (space is a separator) using begin and end iterators + std::vector<std::string> tokens(text_iterator, text_end); + + if (!tokens.empty()) { + // Allocate array of C-strings where we will store tokens + results = new char*[tokens.size()]; + // Store tokens in C-strings array + for (size_t i = 0; i < tokens.size(); ++i) { + size_t cs_size = tokens[i].length() + 1; + char* cs = new char[cs_size]; + strncpy(cs, tokens[i].c_str(), cs_size); + assert(cs[cs_size - 1] == '\0'); + results[i] = cs; + } + // Return number of tokens to calling function + num = tokens.size(); + } + return results; + } +}; + +} // namespace isc::perfdhcp +} // namespace isc + +#endif // COMMAND_OPTIONS_HELPER_H diff --git a/src/bin/perfdhcp/tests/command_options_unittest.cc b/src/bin/perfdhcp/tests/command_options_unittest.cc new file mode 100644 index 0000000..08720d5 --- /dev/null +++ b/src/bin/perfdhcp/tests/command_options_unittest.cc @@ -0,0 +1,1017 @@ +// Copyright (C) 2012-2023 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <cstddef> +#include <fstream> +#include <gtest/gtest.h> +#include <stdint.h> +#include <string> +#include <boost/date_time/posix_time/posix_time.hpp> + +#include <dhcp/iface_mgr.h> +#include <exceptions/exceptions.h> + +#include "command_options_helper.h" + +using namespace std; +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 +/// unit tests on perfdhcp CommandOptions class. +class CommandOptionsTest : public virtual ::testing::Test +{ +public: + /// \brief Default Constructor + CommandOptionsTest() { } + +protected: + /// \brief Parse command line and cleanup + /// + /// The method tokenizes command line to array of C-strings, + /// parses arguments using CommandOptions class to set + /// its data members and de-allocates array of C-strings. + /// + /// \param cmdline Command line to parse. + /// \throws std::bad allocation if tokenization failed. + /// \return true if program has been run in help or version mode ('h' or 'v' flag). + bool process(CommandOptions& opt, const std::string& cmdline) { + return (CommandOptionsHelper::process(opt, cmdline)); + } + + /// \brief Get full path to a file in testdata directory. + /// + /// \param filename filename being appended to absolute + /// path to testdata directory + /// + /// \return full path to a file in testdata directory. + std::string getFullPath(const std::string& filename) const { + std::ostringstream stream; + stream << TEST_DATA_DIR << "/" << filename; + return (stream.str()); + } +}; + +TEST_F(CommandOptionsTest, Defaults) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "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.getRenewRate()); + EXPECT_EQ(0, opt.getReleaseRate()); + EXPECT_EQ(0, opt.getReportDelay()); + EXPECT_EQ(0, opt.getClientsNum()); + + // default mac + const uint8_t mac[6] = { 0x00, 0x0C, 0x01, 0x02, 0x03, 0x04 }; + std::vector<uint8_t> v1 = opt.getMacTemplate(); + ASSERT_EQ(6, v1.size()); + EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac)); + + // Check if DUID is initialized. The DUID-LLT is expected + // to start with DUID_LLT value of 1 and hardware ethernet + // type equal to 1 (HWETHER_TYPE). + const uint8_t duid_llt_and_hw[4] = { 0x0, 0x1, 0x0, 0x1 }; + // We assume DUID-LLT length 14. This includes 4 octets of + // DUID_LLT value, two octets of hardware type, 4 octets + // of time value and 6 octets of variable link layer (MAC) + // address. + const int duid_llt_size = 14; + // DUID is not given from the command line but it is supposed + // to be initialized by the CommandOptions private method + // generateDuidTemplate(). + std::vector<uint8_t> v2 = opt.getDuidTemplate(); + ASSERT_EQ(duid_llt_size, opt.getDuidTemplate().size()); + EXPECT_TRUE(std::equal(v2.begin(), v2.begin() + 4, + duid_llt_and_hw)); + // Check time field contents. + ptime now = microsec_clock::universal_time(); + ptime duid_epoch(from_iso_string("20000101T000000")); + time_period period(duid_epoch, now); + uint32_t duration_sec = period.length().total_seconds(); + // Read time from the template generated. + uint32_t duration_from_template = 0; + memcpy(&duration_from_template, &v2[4], 4); + duration_from_template = htonl(duration_from_template); + // In special cases, we may have overflow in time field + // so we give ourselves the margin of 10 seconds here. + // If time value has been set more then 10 seconds back + // it is safe to compare it with the time value generated + // from now. + if (duration_from_template > 10) { + EXPECT_GE(duration_sec, duration_from_template); + } + + EXPECT_EQ(0, opt.getBase().size()); + EXPECT_EQ(0, opt.getNumRequests().size()); + EXPECT_EQ(0, opt.getPeriod()); + for (size_t i = 0; i < opt.getDropTime().size(); ++i) { + EXPECT_DOUBLE_EQ(1, opt.getDropTime()[i]); + } + ASSERT_EQ(opt.getMaxDrop().size(), opt.getMaxDropPercentage().size()); + for (size_t i = 0; i < opt.getMaxDrop().size(); ++i) { + EXPECT_EQ(0, opt.getMaxDrop()[i]); + EXPECT_EQ(0, opt.getMaxDropPercentage()[i]); + } + EXPECT_EQ("", opt.getLocalName()); + EXPECT_FALSE(opt.isInterface()); + EXPECT_EQ(0, opt.getPreload()); + EXPECT_EQ(0, opt.getLocalPort()); + EXPECT_FALSE(opt.isSeeded()); + EXPECT_EQ(0, opt.getSeed()); + EXPECT_FALSE(opt.isBroadcast()); + EXPECT_FALSE(opt.isRapidCommit()); + EXPECT_FALSE(opt.isUseFirst()); + EXPECT_FALSE(opt.getAddrUnique()); + EXPECT_EQ(-1, opt.getIncreaseElapsedTime()); + EXPECT_EQ(-1, opt.getWaitForElapsedTime()); + EXPECT_EQ(0, opt.getTemplateFiles().size()); + EXPECT_EQ(0, opt.getTransactionIdOffset().size()); + EXPECT_EQ(0, opt.getRandomOffset().size()); + EXPECT_GT(0, opt.getElapsedTimeOffset()); + EXPECT_GT(0, opt.getServerIdOffset()); + EXPECT_GT(0, opt.getRequestedIpOffset()); + EXPECT_EQ("", opt.getDiags()); + EXPECT_EQ("", opt.getWrapped()); + EXPECT_EQ("192.168.0.1", opt.getServerName()); +} + +TEST_F(CommandOptionsTest, HelpVersion) { + // The parser is supposed to return true if 'h' or 'v' options + // are specified. + CommandOptions opt; + EXPECT_TRUE(process(opt, "perfdhcp -h")); + EXPECT_TRUE(process(opt, "perfdhcp -v")); + EXPECT_TRUE(process(opt, "perfdhcp -h -v")); + EXPECT_TRUE(process(opt, "perfdhcp -6 -l ethx -h all")); + EXPECT_TRUE(process(opt, "perfdhcp -l ethx -v all")); + // No 'h' or 'v' option specified. The false value + // should be returned. + EXPECT_FALSE(process(opt, "perfdhcp -l ethx all")); +} + +TEST_F(CommandOptionsTest, CheckAddressUniqueness) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -u -l ethx all")); + EXPECT_TRUE(opt.getAddrUnique()); +} + +TEST_F(CommandOptionsTest, UseFirst) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -1 -B -l ethx all")); + EXPECT_TRUE(opt.isUseFirst()); +} + +TEST_F(CommandOptionsTest, UseCleanOutput) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -C, -l ethx all")); + EXPECT_TRUE(opt.getCleanReport()); + EXPECT_EQ(",", opt.getCleanReportSeparator()); +} + +TEST_F(CommandOptionsTest, UseRelayV6) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -A1 -l ethx all")); + EXPECT_TRUE(opt.isUseRelayedV6()); + // -4 and -A must not coexist + EXPECT_THROW(process(opt, "perfdhcp -4 -A1 -l ethx all"), isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, IpVersion) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -l ethx -c -i all")); + EXPECT_EQ(6, opt.getIpVersion()); + EXPECT_EQ("ethx", opt.getLocalName()); + EXPECT_TRUE(opt.isRapidCommit()); + EXPECT_FALSE(opt.isBroadcast()); + process(opt, "perfdhcp -4 -B -l ethx all"); + EXPECT_EQ(4, opt.getIpVersion()); + EXPECT_TRUE(opt.isBroadcast()); + EXPECT_FALSE(opt.isRapidCommit()); + + // Negative test cases + // -4 and -6 must not coexist + EXPECT_THROW(process(opt, "perfdhcp -4 -6 -l ethx all"), isc::InvalidParameter); + // -6 and -B must not coexist + EXPECT_THROW(process(opt, "perfdhcp -6 -B -l ethx all"), isc::InvalidParameter); + // -c and -4 (default) must not coexist + EXPECT_THROW(process(opt, "perfdhcp -c -l ethx all"), isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, LeaseType) { + CommandOptions opt; + // Check that the -e address-only works for IPv6. + ASSERT_NO_THROW(process(opt, "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(opt, "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(opt, "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(opt, "perfdhcp -4 -l ethx -e prefix-only all"), + InvalidParameter); + // Check that -e prefix-only must not coexist with -T options. + EXPECT_THROW(process(opt, "perfdhcp -6 -l ethx -e prefix-only -T file1.hex" + " -T file2.hex -E 4 all"), InvalidParameter); + +} + +TEST_F(CommandOptionsTest, Rate) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -4 -r 10 -l ethx all")); + EXPECT_EQ(10, opt.getRate()); + + // Negative test cases + // Rate must not be 0 + EXPECT_THROW(process(opt, "perfdhcp -4 -r 0 -l ethx all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, RenewRate) { + CommandOptions opt; + // If -f is specified together with -r the command line should + // be accepted and the renew rate should be set. + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -r 10 -f 10 -l ethx all")); + EXPECT_EQ(10, opt.getRenewRate()); + // Check that the release rate can be set to different value than + // rate specified as -r<rate>. Also, swap -f and -r to make sure + // that order doesn't matter. + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -f 5 -r 10 -l ethx all")); + EXPECT_EQ(5, opt.getRenewRate()); + // Renew rate should also be accepted for DHCPv4 case. + EXPECT_NO_THROW(process(opt, "perfdhcp -4 -f 5 -r 10 -l ethx all")); + EXPECT_EQ(5, opt.getRenewRate()); + // The renew rate should not be greater than the rate. + EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -f 11 -l ethx all"), + isc::InvalidParameter); + // The renew-rate of 0 is invalid. + EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -f 0 -l ethx all"), + isc::InvalidParameter); + // The negative renew-rate is invalid. + EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -f -5 -l ethx all"), + isc::InvalidParameter); + // If -r<rate> is not specified the -f<renew-rate> should not + // be accepted. + EXPECT_THROW(process(opt, "perfdhcp -6 -f 10 -l ethx all"), + isc::InvalidParameter); + // Renew rate should be specified. + EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -f -l ethx all"), + isc::InvalidParameter); + + // -f and -i are mutually exclusive + EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -f 10 -l ethx -i all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, ReleaseRate) { + CommandOptions opt; + // If -F is specified together with -r the command line should + // be accepted and the release rate should be set. + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -r 10 -F 10 -l ethx all")); + EXPECT_EQ(10, opt.getReleaseRate()); + // Check that the release rate can be set to different value than + // rate specified as -r<rate>. Also, swap -F and -r to make sure + // that order doesn't matter. + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -F 5 -r 10 -l ethx all")); + EXPECT_EQ(5, opt.getReleaseRate()); + // The release rate should not be greater than the rate. + EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -F 11 -l ethx all"), + isc::InvalidParameter); + // The release-rate of 0 is invalid. + EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -F 0 -l ethx all"), + isc::InvalidParameter); + // The negative release-rate is invalid. + EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -F -5 -l ethx all"), + isc::InvalidParameter); + // If -r<rate> is not specified the -F<release-rate> should not + // be accepted. + EXPECT_THROW(process(opt, "perfdhcp -6 -F 10 -l ethx all"), + isc::InvalidParameter); + // -F<release-rate> should be usable in IPv6 mode. + EXPECT_NO_THROW(process(opt, "perfdhcp -4 -r 10 -F 10 -l ethx all")); + // Release rate should be specified. + EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -F -l ethx all"), + isc::InvalidParameter); + // -F and -i are mutually exclusive + EXPECT_THROW(process(opt, "perfdhcp -6 -r 10 -F 10 -l ethx -i all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, ReleaseRenew) { + CommandOptions opt; + // It should be possible to specify the -F, -f and -r options. + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -r 10 -F 3 -f 5 -l ethx all")); + EXPECT_EQ(10, opt.getRate()); + EXPECT_EQ(3, opt.getReleaseRate()); + EXPECT_EQ(5, opt.getRenewRate()); + // It should be possible to specify the -F and -f with the values which + // sum is equal to the rate specified as -r<rate>. + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -r 8 -F 3 -f 5 -l ethx all")); + EXPECT_EQ(8, opt.getRate()); + EXPECT_EQ(3, opt.getReleaseRate()); + EXPECT_EQ(5, opt.getRenewRate()); + // Check that the sum of the release and renew rate is not greater + // than the rate specified as -r<rate>. + EXPECT_THROW(process(opt, "perfdhcp -6 -F 6 -f 5 -r 10 -l ethx all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, ReportDelay) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -t 17 -l ethx all")); + EXPECT_EQ(17, opt.getReportDelay()); + + // Negative test cases + // -t must be positive integer + EXPECT_THROW(process(opt, "perfdhcp -t -8 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process(opt, "perfdhcp -t 0 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process(opt, "perfdhcp -t s -l ethx all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, ClientsNum) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -R 200 -l ethx all")); + EXPECT_EQ(200, opt.getClientsNum()); + process(opt, "perfdhcp -R 0 -l ethx all"); + EXPECT_EQ(0, opt.getClientsNum()); + + // Negative test cases + // Number of clients must be non-negative integer + EXPECT_THROW(process(opt, "perfdhcp -R -5 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process(opt, "perfdhcp -R gs -l ethx all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, Base) { + CommandOptions opt; + uint8_t mac[6] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60 }; + uint8_t duid[14] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x10, 0x11, 0x1F, 0x14 }; + // Test DUID and MAC together. + EXPECT_NO_THROW(process(opt, "perfdhcp -b DUID=0101010101010101010110111F14" + " -b MAC=10::20::30::40::50::60" + " -l 127.0.0.1 all")); + std::vector<uint8_t> v1 = opt.getMacTemplate(); + std::vector<uint8_t> v2 = opt.getDuidTemplate(); + EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac)); + EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid)); + // Test valid DUID. + EXPECT_NO_THROW( + process(opt, "perfdhcp -b duid=0101010101010101010110111F14 -l 127.0.0.1 all") + ); + + ASSERT_EQ(sizeof(duid) / sizeof(uint8_t), v2.size()); + EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid)); + // Test mix of upper/lower case letters. + EXPECT_NO_THROW(process(opt, "perfdhcp -b DuiD=0101010101010101010110111F14" + " -b Mac=10::20::30::40::50::60" + " -l 127.0.0.1 all")); + v1 = opt.getMacTemplate(); + v2 = opt.getDuidTemplate(); + EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac)); + EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid)); + // Use "ether" instead of "mac". + EXPECT_NO_THROW(process(opt, "perfdhcp -b ether=10::20::30::40::50::60" + " -l 127.0.0.1 all")); + v1 = opt.getMacTemplate(); + EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac)); + // Use "ETHER" in upper case. + EXPECT_NO_THROW(process(opt, "perfdhcp -b ETHER=10::20::30::40::50::60" + " -l 127.0.0.1 all")); + v1 = opt.getMacTemplate(); + EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac)); + // "t" is invalid character in DUID + EXPECT_THROW(process(opt, "perfdhcp -6 -l ethx -b " + "duid=010101010101010101t110111F14 all"), + isc::InvalidParameter); + // "3x" is invalid value in MAC address + EXPECT_THROW(process(opt, "perfdhcp -b mac=10::2::3x::4::5::6 -l ethx all"), + isc::InvalidParameter); + // Base is not specified + EXPECT_THROW(process(opt, "perfdhcp -b -l ethx all"), + isc::InvalidParameter); + // Typo: should be mac= instead of mc= + EXPECT_THROW(process(opt, "perfdhcp -l ethx -b mc=00:01:02:03::04:05 all"), + isc::InvalidParameter); + // Too short DUID (< 6). + EXPECT_THROW(process(opt, "perfdhcp -l ethx -b duid=00010203 all"), + isc::InvalidParameter); + // Odd number of digits. + EXPECT_THROW(process(opt, "perfdhcp -l ethx -b duid=000102030405060 all"), + isc::InvalidParameter); + // Too short MAC (!= 6). + EXPECT_THROW(process(opt, "perfdhcp -l ethx -b mac=00:01:02:04 all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, DropTime) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -l ethx -d 12 all")); + ASSERT_EQ(2, opt.getDropTime().size()); + EXPECT_DOUBLE_EQ(12, opt.getDropTime()[0]); + EXPECT_DOUBLE_EQ(1, opt.getDropTime()[1]); + + EXPECT_NO_THROW(process(opt, "perfdhcp -l ethx -d 2 -d 4.7 all")); + ASSERT_EQ(2, opt.getDropTime().size()); + EXPECT_DOUBLE_EQ(2, opt.getDropTime()[0]); + EXPECT_DOUBLE_EQ(4.7, opt.getDropTime()[1]); + + // Negative test cases + // Drop time must not be negative + EXPECT_THROW(process(opt, "perfdhcp -l ethx -d -2 -d 4.7 all"), + isc::InvalidParameter); + EXPECT_THROW(process(opt, "perfdhcp -l ethx -d -9.1 -d 0 all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, TimeOffset) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -l ethx -T file1.x -T file2.x -E 4 all")); + EXPECT_EQ(4, opt.getElapsedTimeOffset()); + + // Negative test cases + // Argument -E must be used with -T + EXPECT_THROW(process(opt, "perfdhcp -l ethx -E 3 -i all"), + isc::InvalidParameter); + // Value in -E not specified + EXPECT_THROW(process(opt, "perfdhcp -l ethx -T file.x -E -i all"), + isc::InvalidParameter); + // Value for -E must not be negative + EXPECT_THROW(process(opt, "perfdhcp -l ethx -E -3 -T file.x all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, ExchangeMode) { + CommandOptions opt; + process(opt, "perfdhcp -l ethx -i all"); + EXPECT_EQ(CommandOptions::DO_SA, opt.getExchangeMode()); + + // Negative test cases + // No template file specified + EXPECT_THROW(process(opt, "perfdhcp -i -l ethx -X 3 all"), + isc::InvalidParameter); + // Offsets can't be used in simple exchanges (-i) + EXPECT_THROW(process(opt, "perfdhcp -i -l ethx -O 2 -T file.x all"), + isc::InvalidParameter); + EXPECT_THROW(process(opt, "perfdhcp -i -l ethx -E 3 -T file.x all"), + isc::InvalidParameter); + EXPECT_THROW(process(opt, "perfdhcp -i -l ethx -S 1 -T file.x all"), + isc::InvalidParameter); + EXPECT_THROW(process(opt, "perfdhcp -i -l ethx -I 2 -T file.x all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, Offsets) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -E5 -4 -I 2 -S3 -O 30 -X7 -l ethx " + "-X3 -T file1.x -T file2.x all")); + EXPECT_EQ(2, opt.getRequestedIpOffset()); + EXPECT_EQ(5, opt.getElapsedTimeOffset()); + EXPECT_EQ(3, opt.getServerIdOffset()); + ASSERT_EQ(2, opt.getRandomOffset().size()); + EXPECT_EQ(30, opt.getRandomOffset()[0]); + EXPECT_EQ(30, opt.getRandomOffset()[1]); + ASSERT_EQ(2, opt.getTransactionIdOffset().size()); + EXPECT_EQ(7, opt.getTransactionIdOffset()[0]); + EXPECT_EQ(3, opt.getTransactionIdOffset()[1]); + + // Negative test cases + // IP offset/IA_NA offset must be positive + EXPECT_THROW(process(opt, "perfdhcp -6 -I 0 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process(opt, "perfdhcp -6 -I -4 -l ethx all"), + isc::InvalidParameter); + + // \todo other negative cases +} + +TEST_F(CommandOptionsTest, LocalPort) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -l ethx -L 2000 all")); + EXPECT_EQ(2000, opt.getLocalPort()); + + // Negative test cases + // Local port must be between 0..65535 + EXPECT_THROW(process(opt, "perfdhcp -l ethx -L -2 all"), + isc::InvalidParameter); + EXPECT_THROW(process(opt, "perfdhcp -l ethx -L all"), + isc::InvalidParameter); + EXPECT_THROW(process(opt, "perfdhcp -l ethx -L 65540 all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, Preload) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -1 -P 3 -l ethx all")); + EXPECT_EQ(3, opt.getPreload()); + + // Negative test cases + // Number of preload packages must not be negative integer + EXPECT_THROW(process(opt, "perfdhcp -P -1 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process(opt, "perfdhcp -P -3 -l ethx all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, Seed) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -P 2 -s 23 -l ethx all")); + EXPECT_EQ(23, opt.getSeed()); + EXPECT_TRUE(opt.isSeeded()); + + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -P 2 -s 0 -l ethx all")); + EXPECT_EQ(0, opt.getSeed()); + EXPECT_FALSE(opt.isSeeded()); + + // Negative test cases + // Seed must be non-negative integer + EXPECT_THROW(process(opt, "perfdhcp -6 -P 2 -s -5 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process(opt, "perfdhcp -6 -P 2 -s -l ethx all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, TemplateFiles) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -T file1.x -l ethx all")); + ASSERT_EQ(1, opt.getTemplateFiles().size()); + EXPECT_EQ("file1.x", opt.getTemplateFiles()[0]); + + EXPECT_NO_THROW(process(opt, "perfdhcp -T file1.x -s 12 -w start -T file2.x -4 -l ethx all")); + ASSERT_EQ(2, opt.getTemplateFiles().size()); + EXPECT_EQ("file1.x", opt.getTemplateFiles()[0]); + EXPECT_EQ("file2.x", opt.getTemplateFiles()[1]); + + // Negative test cases + // No template file specified + EXPECT_THROW(process(opt, "perfdhcp -s 12 -T -l ethx all"), + isc::InvalidParameter); + // Too many template files specified + EXPECT_THROW(process(opt, "perfdhcp -s 12 -l ethx -T file.x " + "-T file.x -T file.x all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, Wrapped) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -B -w start -i -l ethx all")); + EXPECT_EQ("start", opt.getWrapped()); + + // Negative test cases + // Missing command after -w, expected start/stop + EXPECT_THROW(process(opt, "perfdhcp -B -i -l ethx -w all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, Diagnostics) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -l ethx -i -x asTe all")); + EXPECT_EQ("asTe", opt.getDiags()); + + // Negative test cases + // No diagnostics string specified + EXPECT_THROW(process(opt, "perfdhcp -l ethx -i -x all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, MaxDrop) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -D 25 -l ethx all")); + EXPECT_EQ(25, opt.getMaxDrop()[0]); + EXPECT_NO_THROW(process(opt, "perfdhcp -D 25 -l ethx -D 15 all")); + EXPECT_EQ(25, opt.getMaxDrop()[0]); + EXPECT_EQ(15, opt.getMaxDrop()[1]); + + EXPECT_NO_THROW(process(opt, "perfdhcp -D 15% -l ethx all")); + EXPECT_EQ(15, opt.getMaxDropPercentage()[0]); + EXPECT_NO_THROW(process(opt, "perfdhcp -D 15% -D25% -l ethx all")); + EXPECT_EQ(15, opt.getMaxDropPercentage()[0]); + EXPECT_EQ(25, opt.getMaxDropPercentage()[1]); + EXPECT_NO_THROW(process(opt, "perfdhcp -D 1% -D 99% -l ethx all")); + EXPECT_EQ(1, opt.getMaxDropPercentage()[0]); + EXPECT_EQ(99, opt.getMaxDropPercentage()[1]); + + // Negative test cases + // Too many -D<value> options + EXPECT_THROW(process(opt, "perfdhcp -D 0% -D 1 -l ethx -D 3 all"), + isc::InvalidParameter); + // Too many -D<value%> options + EXPECT_THROW(process(opt, "perfdhcp -D 99% -D 13% -l ethx -D 10% all"), + isc::InvalidParameter); + // Percentage is out of bounds + EXPECT_THROW(process(opt, "perfdhcp -D101% -D 13% -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process(opt, "perfdhcp -D0% -D 13% -l ethx all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, NumRequest) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -n 1000 -l ethx all")); + EXPECT_EQ(1000, opt.getNumRequests()[0]); + EXPECT_NO_THROW(process(opt, "perfdhcp -n 5 -n 500 -l ethx all")); + EXPECT_EQ(5, opt.getNumRequests()[0]); + EXPECT_EQ(500, opt.getNumRequests()[1]); + + // Negative test cases + // Too many -n<value> parameters, expected maximum 2 + EXPECT_THROW(process(opt, "perfdhcp -n 1 -n 2 -l ethx -n3 all"), + isc::InvalidParameter); + // Num request must be positive integer + EXPECT_THROW(process(opt, "perfdhcp -n 1 -n -22 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process(opt, "perfdhcp -n 0 -l ethx all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, Period) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -p 120 -l ethx all")); + EXPECT_EQ(120, opt.getPeriod()); + + // Negative test cases + // Test period must be positive integer + EXPECT_THROW(process(opt, "perfdhcp -p 0 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process(opt, "perfdhcp -p -3 -l ethx all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, Interface) { + // In order to make this test portable we need to know + // at least one interface name on OS where test is run. + // Interface Manager has ability to detect interfaces. + // Although we don't call initIsInterface explicitly + // here it is called by CommandOptions object internally + // so this function is covered by the test. + dhcp::IfaceMgr& iface_mgr = dhcp::IfaceMgr::instance(); + const dhcp::IfaceCollection& ifaces = iface_mgr.getIfaces(); + std::string iface_name; + CommandOptions opt; + // The local loopback interface should be available. + // If no interface have been found for any reason we should + // not fail this test. + if (!ifaces.empty()) { + // Get the name of the interface we detected. + iface_name = (*ifaces.begin())->getName(); + // Use the name in the command parser. + ASSERT_NO_THROW(process(opt, "perfdhcp -4 -l " + iface_name + " abc")); + // We expect that command parser will detect that argument + // specified along with '-l' is the interface name. + EXPECT_TRUE(opt.isInterface()); + + // If neither interface nor server is specified then + // exception is expected to be thrown. + EXPECT_THROW(process(opt, "perfdhcp -4"), isc::InvalidParameter); + } +} + +TEST_F(CommandOptionsTest, Server) { + CommandOptions opt; + // There is at least server parameter needed. If server is not + // specified the local interface must be specified. + // The server value equal to 'all' means use broadcast. + ASSERT_NO_THROW(process(opt, "perfdhcp all")); + // Once command line is parsed we expect that server name is + // set to broadcast address because 'all' was specified. + EXPECT_TRUE(opt.isBroadcast()); + // The broadcast address is 255.255.255.255. + EXPECT_EQ(DHCP_IPV4_BROADCAST_ADDRESS, opt.getServerName()); + + // When all is specified for DHCPv6 mode we expect + // FF02::1:2 as a server name which means All DHCP + // servers and relay agents in local network segment + ASSERT_NO_THROW(process(opt, "perfdhcp -6 all")); + EXPECT_EQ(ALL_DHCP_RELAY_AGENTS_AND_SERVERS, opt.getServerName()); + + // When server='servers' in DHCPv6 mode we expect + // FF05::1:3 as server name which means All DHCP + // servers in local network. + ASSERT_NO_THROW(process(opt, "perfdhcp -6 servers")); + EXPECT_EQ(ALL_DHCP_SERVERS, opt.getServerName()); + + // If server name is neither 'all' nor 'servers' + // the given argument value is expected to be + // returned. + ASSERT_NO_THROW(process(opt, "perfdhcp -6 abc")); + EXPECT_EQ("abc", opt.getServerName()); +} + +TEST_F(CommandOptionsTest, LoadMacsFromFile) { + CommandOptions opt; + + std::string mac_list_full_path = getFullPath("mac-list.txt"); + std::ostringstream cmd; + cmd << "perfdhcp -M " << mac_list_full_path << " abc"; + EXPECT_NO_THROW(process(opt, cmd.str())); + EXPECT_EQ(mac_list_full_path, opt.getMacListFile()); + + const CommandOptions::MacAddrsVector& m = opt.getMacsFromFile(); + EXPECT_EQ(4, m.size()); +} + +TEST_F(CommandOptionsTest, LoadRelay4AddrFromFile) { + CommandOptions opt; + std::string relay_addr_list_full_path = getFullPath("relay4-list.txt"); + std::ostringstream cmd; + cmd << "perfdhcp -4 -J " << relay_addr_list_full_path << " abc"; + EXPECT_NO_THROW(process(opt, cmd.str())); + EXPECT_EQ(relay_addr_list_full_path, opt.getRelayAddrListFile()); + EXPECT_TRUE(opt.checkMultiSubnet()); + EXPECT_EQ(5, opt.getRelayAddrList().size()); +} + +TEST_F(CommandOptionsTest, LoadRelay6AddrFromFile) { + CommandOptions opt; + std::string relay_addr_list_full_path = getFullPath("relay6-list.txt"); + std::ostringstream cmd; + cmd << "perfdhcp -6 -J " << relay_addr_list_full_path << " abc"; + EXPECT_NO_THROW(process(opt, cmd.str())); + EXPECT_EQ(relay_addr_list_full_path, opt.getRelayAddrListFile()); + EXPECT_TRUE(opt.checkMultiSubnet()); + EXPECT_EQ(2, opt.getRelayAddrList().size()); +} + +TEST_F(CommandOptionsTest, RelayAddr6ForVersion4) { + CommandOptions opt; + std::string relay_addr_list_full_path = getFullPath("relay6-list.txt"); + std::ostringstream cmd; + cmd << "perfdhcp -4 -J " << relay_addr_list_full_path << " abc"; + EXPECT_THROW(process(opt, cmd.str()), isc::InvalidParameter); + EXPECT_FALSE(opt.checkMultiSubnet()); + EXPECT_EQ(0, opt.getRelayAddrList().size()); +} + +TEST_F(CommandOptionsTest, RelayAddr4ForVersion6) { + CommandOptions opt; + std::string relay_addr_list_full_path = getFullPath("relay4-list.txt"); + std::ostringstream cmd; + cmd << "perfdhcp -6 -J " << relay_addr_list_full_path << " abc"; + EXPECT_THROW(process(opt, cmd.str()), isc::InvalidParameter); + EXPECT_FALSE(opt.checkMultiSubnet()); + EXPECT_EQ(0, opt.getRelayAddrList().size()); +} + + +TEST_F(CommandOptionsTest, LoadMacsFromFileNegativeCases) { + CommandOptions opt; + // Negative test cases + // Too many -M parameters, expected only 1 + EXPECT_THROW(process(opt, "perfdhcp -M foo -M foo1 all"), isc::InvalidParameter); + // -M option can't use with -b option + EXPECT_THROW(process(opt, "perfdhcp -M foo -b mac=1234 all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, ElapsedTime) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -y 3 -Y 10 192.168.0.1")); + + EXPECT_EQ(3, opt.getIncreaseElapsedTime()); + EXPECT_EQ(10, opt.getWaitForElapsedTime()); +} + +TEST_F(CommandOptionsTest, UseRelayV6OptionsWithoutV6) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -A1 --or 32,00000E10 -l ethx all")); + EXPECT_TRUE(opt.isUseRelayedV6()); + EXPECT_EQ(1, opt.getRelayOpts().size()); + + // --or must be used together with -6 + EXPECT_THROW(process(opt, "perfdhcp -A1 --or 32,00000E10 -l ethx all"), isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, UseRelayV6OptionsWithoutRelayEncapsulation) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -A1 --or 32,00000E10 -l ethx all")); + EXPECT_TRUE(opt.isUseRelayedV6()); + EXPECT_EQ(1, opt.getRelayOpts().size()); + + // --or must be used together with -A + EXPECT_THROW(process(opt, "perfdhcp -6 --or 32,00000E10 -l ethx all"), isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, UseMultipleRelayV6Options) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -A1 --or 32,00000E10 --or " + "23,20010DB800010000000000000000CAFE -l ethx all")); + EXPECT_TRUE(opt.isUseRelayedV6()); + // 2 options expected at 1st level of encapsulation + EXPECT_EQ(2, opt.getRelayOpts().size()); + // no options expected at 2nd level of encapsulation + EXPECT_THROW(opt.getRelayOpts(2), isc::OutOfRange); +} + +TEST_F(CommandOptionsTest, UseRelayV6OptionsWithMultiSubnets) { + CommandOptions opt; + std::string relay_addr_list_full_path = getFullPath("relay6-list.txt"); + std::ostringstream cmd; + cmd << "perfdhcp -6 -J " << relay_addr_list_full_path + << " -A1 --or 32,00000E10 --or 23,20010DB800010000000000000000CAFE -l ethx all"; + EXPECT_NO_THROW(process(opt, cmd.str())); + EXPECT_EQ(relay_addr_list_full_path, opt.getRelayAddrListFile()); + EXPECT_TRUE(opt.checkMultiSubnet()); + EXPECT_EQ(2, opt.getRelayAddrList().size()); + EXPECT_TRUE(opt.isUseRelayedV6()); + // 2 options expected at 1st level of encapsulation + EXPECT_EQ(2, opt.getRelayOpts().size()); + // no options expected at 2nd level of encapsulation + EXPECT_THROW(opt.getRelayOpts(2), isc::OutOfRange); +} + +TEST_F(CommandOptionsTest, UseRelayV6OptionsNoComma) { + CommandOptions opt; + + // --or must be followed by encapsulation-level, colon, option code, a comma and hexstring + // in case encapsulation-level and colon are skipped, encapsulation-level is by default 1 + EXPECT_THROW(process(opt, "perfdhcp -6 --or 3200000E10 -l ethx all"), isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, UseRelayV6OptionsNegativeOptionCode) { + CommandOptions opt; + + // --or must be followed by encapsulation-level, colon, positive option code, a comma and hexstring + // in case encapsulation-level and colon are skipped, encapsulation-level is by default 1 + EXPECT_THROW(process(opt, "perfdhcp -6 --or -32,00000E10 -l ethx all"), isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, UseRelayV6OptionsWrongHexstring) { + CommandOptions opt; + + // --or hexstring containing char Z which is not correct + EXPECT_THROW(process(opt, "perfdhcp -6 --or 32,Z0000E10 -l ethx all"), isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, UseRelayV6OptionsWithEncapsulationLevel) { + CommandOptions opt; + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -A1 --or 1:32,00000E10 -l ethx all")); + EXPECT_TRUE(opt.isUseRelayedV6()); + EXPECT_EQ(1, opt.getRelayOpts().size()); +} + +TEST_F(CommandOptionsTest, UseRelayV6OptionsWithNegativeEncapsulationLevel) { + CommandOptions opt; + + // provided Relayed option encapsulation level must be a positive integer. + EXPECT_THROW(process(opt, "perfdhcp -6 -A1 --or -1:32,00000E10 -l ethx all"), isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, UseRelayV6OptionsWithZeroEncapsulationLevel) { + CommandOptions opt; + + // provided Relayed option encapsulation level must be a positive integer. + EXPECT_THROW(process(opt, "perfdhcp -6 -A1 --or 0:32,00000E10 -l ethx all"), isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, UseRelayV6OptionsWithWrongEncapsulationLevel) { + CommandOptions opt; + + // provided Relayed option encapsulation level must be a positive integer. + EXPECT_THROW(process(opt, "perfdhcp -6 -A1 --or x:32,00000E10 -l ethx all"), isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, UseRelayV6OptionsWithEncapsulationLevelValueTwo) { + CommandOptions opt; + + // Relayed option encapsulation level supports only value 1 at the moment. + EXPECT_THROW(process(opt, "perfdhcp -6 -A1 --or 2:32,00000E10 -l ethx all"), isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, UseRelayV6OptionsDuplicated) { + CommandOptions opt; + + // multiple relayed options with the same option code are supported. + EXPECT_NO_THROW(process(opt, "perfdhcp -6 -A1 --or 1:32,00000E10 --or 32,00000E11 -l ethx all")); + EXPECT_TRUE(opt.isUseRelayedV6()); + EXPECT_EQ(2, opt.getRelayOpts().size()); +} + + diff --git a/src/bin/perfdhcp/tests/localized_option_unittest.cc b/src/bin/perfdhcp/tests/localized_option_unittest.cc new file mode 100644 index 0000000..6b849bd --- /dev/null +++ b/src/bin/perfdhcp/tests/localized_option_unittest.cc @@ -0,0 +1,42 @@ +// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> +#include <gtest/gtest.h> + +#include <dhcp/option.h> +#include <dhcp/dhcp6.h> + +#include <boost/scoped_ptr.hpp> + +#include "../localized_option.h" + +using namespace std; +using namespace isc; +using namespace isc::dhcp; +using namespace isc::perfdhcp; + +namespace { + +TEST(LocalizedOptionTest, Constructor) { + OptionBuffer opt_buf; + // Create option with default offset. + boost::scoped_ptr<LocalizedOption> opt1(new LocalizedOption(Option::V6, + D6O_CLIENTID, + opt_buf)); + EXPECT_EQ(Option::V6, opt1->getUniverse()); + EXPECT_EQ(D6O_CLIENTID, opt1->getType()); + EXPECT_EQ(0, opt1->getOffset()); + + // Create option with non-default offset. + boost::scoped_ptr<LocalizedOption> opt2(new LocalizedOption(Option::V6, + D6O_CLIENTID, + opt_buf, + 40)); + EXPECT_EQ(40, opt2->getOffset()); +} + +} diff --git a/src/bin/perfdhcp/tests/packet_storage_unittest.cc b/src/bin/perfdhcp/tests/packet_storage_unittest.cc new file mode 100644 index 0000000..157da2b --- /dev/null +++ b/src/bin/perfdhcp/tests/packet_storage_unittest.cc @@ -0,0 +1,199 @@ +// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include "../packet_storage.h" +#include <dhcp/dhcp6.h> +#include <dhcp/pkt6.h> + +#include <gtest/gtest.h> + +namespace { + +using namespace isc; +using namespace isc::dhcp; +using namespace perfdhcp; + +/// @todo Implement the tests which use Pkt4 objects once the support for +/// DHCPv4 renewals / releases is added. + +/// The number of packets in the test storage. +const unsigned int STORAGE_SIZE = 20; + +/// Test fixture class for PacketStorage container testing. +class PacketStorageTest : public ::testing::Test { +public: + /// \brief Constructor, initializes the storage for each test. + PacketStorageTest() { + for (uint32_t i = 0; i < STORAGE_SIZE; ++i) { + storage_.append(createPacket6(DHCPV6_REPLY, i)); + } + } + + /// \brief Creates an instance of the Pkt6. + /// + /// \param packet_type A type of the packet. + /// \param transid Transaction id. + /// \return An instance of the Pkt6. + Pkt6Ptr createPacket6(const uint16_t packet_type, + const uint32_t transid) { + return (Pkt6Ptr(new Pkt6(packet_type, transid))); + } + + /// Packet storage under test. + PacketStorage<Pkt6> storage_; + +}; + +// This test verifies that the packets in the storage can be accessed +// sequentially and when a packet is returned, it is removed from the +// storage. It also verifies the correctness of the behaviour of the +// empty() and size() functions. +TEST_F(PacketStorageTest, getNext) { + ASSERT_EQ(STORAGE_SIZE, storage_.size()); + for (int i = 0; i < STORAGE_SIZE; ++i) { + Pkt6Ptr packet = storage_.getNext(); + ASSERT_TRUE(packet) << "NULL packet returned by storage_.getNext() for" + << " iteration number " << i; + EXPECT_EQ(i, packet->getTransid()); + EXPECT_EQ(STORAGE_SIZE - i - 1, storage_.size()); + } + EXPECT_TRUE(storage_.empty()); + // When storage is empty, the attempt to get the next packet should + // result in returning NULL pointer. + EXPECT_FALSE(storage_.getNext()); + // Let's try it again to see if the previous call to getNext didn't + // put the storage into the state in which the subsequent calls to + // getNext would result in incorrect behaviour. + EXPECT_FALSE(storage_.getNext()); + + // Let's add a new packet to the empty storage to check that storage + // "recovers" from being empty, i.e. that the internal indicator + // which points to current packet reinitializes correctly. + storage_.append(createPacket6(DHCPV6_REPLY, 100)); + ASSERT_EQ(1, storage_.size()); + Pkt6Ptr packet = storage_.getNext(); + EXPECT_EQ(100, packet->getTransid()); + EXPECT_FALSE(storage_.getNext()); +} + +// This test verifies that the packets in the storage can be accessed +// randomly and when a packet is returned, it is removed from the +// storage. It also verifies the correctness of the behaviour of the +// empty() and size() functions. +TEST_F(PacketStorageTest, getRandom) { + ASSERT_EQ(STORAGE_SIZE, storage_.size()); + int cnt_equals = 0; + for (int i = 0; i < STORAGE_SIZE; ++i) { + Pkt6Ptr packet = storage_.getRandom(); + ASSERT_TRUE(packet) << "NULL packet returned by storage_.getRandom()" + " for iteration number " << i; + EXPECT_EQ(STORAGE_SIZE - i - 1, storage_.size()); + cnt_equals += (i == packet->getTransid() ? 1 : 0); + } + // If the number of times id is equal to i, is the same as the number + // of elements then they were NOT accessed randomly. + // The odds of 20 elements being randomly accessed sequential order + // is nil isn't it? + EXPECT_NE(cnt_equals, STORAGE_SIZE); + + EXPECT_TRUE(storage_.empty()); + // When storage is empty, the attempt to get the random packet should + // result in returning NULL pointer. + EXPECT_FALSE(storage_.getRandom()); + // Let's try it again to see if the previous call to getRandom didn't + // put the storage into the state in which the subsequent calls to + // getRandom would result in incorrect behaviour. + EXPECT_FALSE(storage_.getRandom()); + + // Let's add a new packet to the empty storage to check that storage + // "recovers" from being empty, i.e. that the internal indicator + // which points to the current packet reinitializes correctly. + storage_.append(createPacket6(DHCPV6_REPLY, 100)); + ASSERT_EQ(1, storage_.size()); + Pkt6Ptr packet = storage_.getRandom(); + ASSERT_TRUE(packet); + EXPECT_EQ(100, packet->getTransid()); + EXPECT_FALSE(storage_.getRandom()); +} + +// This test verifies that the packets in the storage can be accessed +// either randomly or sequentially in the same time. It verifies that +// each returned packet is removed from the storage. +TEST_F(PacketStorageTest, getNextAndRandom) { + ASSERT_EQ(STORAGE_SIZE, storage_.size()); + for (int i = 0; i < STORAGE_SIZE / 2; ++i) { + Pkt6Ptr packet_random = storage_.getRandom(); + ASSERT_TRUE(packet_random) << "NULL packet returned by" + " storage_.getRandom() for iteration number " << i; + EXPECT_EQ(STORAGE_SIZE - 2 *i - 1, storage_.size()); + Pkt6Ptr packet_seq = storage_.getNext(); + ASSERT_TRUE(packet_seq) << "NULL packet returned by" + " storage_.getNext() for iteration number " << i; + EXPECT_EQ(STORAGE_SIZE - 2 * i - 2, storage_.size()); + } + EXPECT_TRUE(storage_.empty()); + EXPECT_FALSE(storage_.getRandom()); + EXPECT_FALSE(storage_.getNext()); + + // Append two packets to the storage to check if it can "recover" + // from being empty and that new elements can be accessed. + storage_.append(createPacket6(DHCPV6_REPLY, 100)); + storage_.append(createPacket6(DHCPV6_REPLY, 101)); + ASSERT_EQ(2, storage_.size()); + // The newly added elements haven't been accessed yet. So, if we + // call getNext the first one should be returned. + Pkt6Ptr packet_next = storage_.getNext(); + ASSERT_TRUE(packet_next); + // The first packet has transaction id equal to 100. + EXPECT_EQ(100, packet_next->getTransid()); + // There should be just one packet left in the storage. + ASSERT_EQ(1, storage_.size()); + // The call to getRandom should return the sole packet from the + // storage. + Pkt6Ptr packet_random = storage_.getRandom(); + ASSERT_TRUE(packet_random); + EXPECT_EQ(101, packet_random->getTransid()); + // Any further calls to getRandom and getNext should return NULL. + EXPECT_FALSE(storage_.getRandom()); + EXPECT_FALSE(storage_.getNext()); +} + +// This test verifies that all packets are removed from the storage when +// clear() function is invoked. +TEST_F(PacketStorageTest, clearAll) { + ASSERT_EQ(STORAGE_SIZE, storage_.size()); + ASSERT_NO_THROW(storage_.clear()); + EXPECT_TRUE(storage_.empty()); +} + +// This test verifies that a set of packets can be removed from the +// storage when a number of packets to be removed is specified. If +// number of packets to be removed exceeds the storage size, all +// packets should be removed. +TEST_F(PacketStorageTest, clear) { + // Initially storage should have 20 elements. + ASSERT_EQ(STORAGE_SIZE, storage_.size()); + // Remove 10 of them. + ASSERT_NO_THROW(storage_.clear(10)); + // We should have 10 remaining. + ASSERT_EQ(10, storage_.size()); + + // Check that the retrieval still works after partial clear. + EXPECT_TRUE(storage_.getNext()); + EXPECT_TRUE(storage_.getRandom()); + // We should have 10 - 2 = 8 packets in the storage after retrieval. + ASSERT_EQ(8, storage_.size()); + + // Try to remove more elements that actually is. It + // should result in removal of all elements. + ASSERT_NO_THROW(storage_.clear(15)); + EXPECT_TRUE(storage_.empty()); +} + + +} // anonymous namespace diff --git a/src/bin/perfdhcp/tests/perf_pkt4_unittest.cc b/src/bin/perfdhcp/tests/perf_pkt4_unittest.cc new file mode 100644 index 0000000..b162051 --- /dev/null +++ b/src/bin/perfdhcp/tests/perf_pkt4_unittest.cc @@ -0,0 +1,425 @@ +// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> +#include <iostream> +#include <sstream> +#include <arpa/inet.h> +#include <gtest/gtest.h> + +#include <asiolink/io_address.h> +#include <dhcp/option.h> +#include <dhcp/dhcp4.h> + +#include <boost/scoped_ptr.hpp> + +#include "../localized_option.h" +#include "../perf_pkt4.h" + +using namespace std; +using namespace isc; +using namespace isc::asiolink; +using namespace isc::dhcp; +using namespace isc::perfdhcp; + +typedef PerfPkt4::LocalizedOptionPtr LocalizedOptionPtr; + +namespace { + +// A dummy MAC address, padded with 0s +const uint8_t dummyChaddr[16] = {0, 1, 2, 3, 4, 5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; + +// Let's use some creative test content here (128 chars + \0) +const uint8_t dummyFile[] = "Lorem ipsum dolor sit amet, consectetur " + "adipiscing elit. Proin mollis placerat metus, at " + "lacinia orci ornare vitae. Mauris amet."; + +// Yet another type of test content (64 chars + \0) +const uint8_t dummySname[] = "Lorem ipsum dolor sit amet, consectetur " + "adipiscing elit posuere."; + +class PerfPkt4Test : public ::testing::Test { +public: + PerfPkt4Test() { + } + + /// \brief Returns buffer with sample DHCPDISCOVER message. + /// + /// This method creates buffer containing on-wire data of + /// DHCPDICOSVER message. This buffer is used by tests below + /// to create DHCPv4 test packets. + /// + /// \return vector containing on-wire data + std::vector<uint8_t>& capture() { + + // That is only part of the header. It contains all "short" fields, + // larger fields are constructed separately. + uint8_t hdr[] = { + 1, 6, 6, 13, // op, htype, hlen, hops, + 0x12, 0x34, 0x56, 0x78, // transaction-id + 0, 42, 0x80, 0x00, // 42 secs, BROADCAST flags + 192, 0, 2, 1, // ciaddr + 1, 2, 3, 4, // yiaddr + 192, 0, 2, 255, // siaddr + 255, 255, 255, 255, // giaddr + }; + + // cppcheck-suppress variableScope + uint8_t v4Opts[] = { + DHO_HOST_NAME, 3, 0, 1, 2, // Host name option. + DHO_BOOT_SIZE, 3, 10, 11, 12, // Boot file size option + DHO_MERIT_DUMP, 3, 20, 21, 22, // Merit dump file + DHO_DHCP_MESSAGE_TYPE, 1, 1, // DHCP message type. + 128, 3, 30, 31, 32, + 254, 3, 40, 41, 42, + }; + + // Initialize the vector with the header fields defined above. + static std::vector<uint8_t> buf(hdr, hdr + sizeof(hdr)); + + // If this is a first call to this function. Initialize + // remaining data. + if (buf.size() == sizeof(hdr)) { + + // Append the large header fields. + std::copy(dummyChaddr, dummyChaddr + Pkt4::MAX_CHADDR_LEN, + back_inserter(buf)); + std::copy(dummySname, dummySname + Pkt4::MAX_SNAME_LEN, + back_inserter(buf)); + std::copy(dummyFile, dummyFile + Pkt4::MAX_FILE_LEN, + back_inserter(buf)); + + // Append magic cookie. + buf.push_back(0x63); + buf.push_back(0x82); + buf.push_back(0x53); + buf.push_back(0x63); + + // Append options. + std::copy(v4Opts, v4Opts + sizeof(v4Opts), back_inserter(buf)); + } + return buf; + } +}; + +TEST_F(PerfPkt4Test, Constructor) { + // Initialize some dummy payload. + uint8_t data[250]; + for (uint8_t i = 0; i < 250; ++i) { + data[i] = i; + } + + // Test constructor to be used for incoming messages. + // Use default (1) offset value and don't specify transaction id. + const size_t offset_transid[] = { 1, 10 }; + boost::scoped_ptr<PerfPkt4> pkt1(new PerfPkt4(data, + sizeof(data), + offset_transid[0])); + EXPECT_EQ(1, pkt1->getTransidOffset()); + + // Test constructor to be used for outgoing messages. + // Use non-zero offset and specify transaction id. + const uint32_t transid = 0x010203; + boost::scoped_ptr<PerfPkt4> pkt2(new PerfPkt4(data, sizeof(data), + offset_transid[1], + transid)); + EXPECT_EQ(transid, pkt2->getTransid()); + EXPECT_EQ(offset_transid[1], pkt2->getTransidOffset()); + + // Test default constructor. Transaction id offset is expected to be 1. + boost::scoped_ptr<PerfPkt4> pkt3(new PerfPkt4(data, sizeof(data))); + EXPECT_EQ(1, pkt3->getTransidOffset()); +} + +TEST_F(PerfPkt4Test, RawPack) { + // Create new packet. + std::vector<uint8_t> buf = capture(); + boost::scoped_ptr<PerfPkt4> pkt(new PerfPkt4(&buf[0], buf.size())); + + // Initialize options data. + uint8_t buf_hostname[] = { DHO_HOST_NAME, 3, 4, 5, 6 }; + uint8_t buf_boot_filesize[] = { DHO_BOOT_SIZE, 3, 1, 2, 3 }; + OptionBuffer vec_hostname(buf_hostname + 2, + buf_hostname + sizeof(buf_hostname)); + OptionBuffer vec_boot_filesize(buf_boot_filesize + 2, + buf_boot_filesize + sizeof(buf_hostname)); + + // Create options objects. + const size_t offset_hostname = 240; + LocalizedOptionPtr pkt_hostname(new LocalizedOption(Option::V4, + DHO_HOST_NAME, + vec_hostname, + offset_hostname)); + const size_t offset_boot_filesize = 245; + LocalizedOptionPtr pkt_boot_filesize(new LocalizedOption(Option::V4, + DHO_BOOT_SIZE, + vec_boot_filesize, + offset_boot_filesize)); + + // Try to add options to packet. + ASSERT_NO_THROW(pkt->addOption(pkt_boot_filesize)); + ASSERT_NO_THROW(pkt->addOption(pkt_hostname)); + + // We have valid options addedwith valid offsets so + // pack operation should succeed. + ASSERT_TRUE(pkt->rawPack()); + + // Buffer should now contain new values of DHO_HOST_NAME and + // DHO_BOOT_SIZE options. + util::OutputBuffer pkt_output = pkt->getBuffer(); + ASSERT_EQ(buf.size(), pkt_output.getLength()); + const uint8_t* out_buf_data = + static_cast<const uint8_t*>(pkt_output.getData()); + + // Check if options we read from buffer is valid. + EXPECT_EQ(0, memcmp(buf_hostname, + out_buf_data + offset_hostname, + sizeof(buf_hostname))); + EXPECT_EQ(0, memcmp(buf_boot_filesize, + out_buf_data + offset_boot_filesize, + sizeof(buf_boot_filesize))); +} + +TEST_F(PerfPkt4Test, RawUnpack) { + // Create new packet. + std::vector<uint8_t> buf = capture(); + boost::scoped_ptr<PerfPkt4> pkt(new PerfPkt4(&buf[0], buf.size())); + + // Create options (existing in the packet) and specify their offsets. + const size_t offset_merit = 250; + LocalizedOptionPtr opt_merit(new LocalizedOption(Option::V4, + DHO_MERIT_DUMP, + OptionBuffer(), + offset_merit)); + + const size_t offset_msg_type = 255; + LocalizedOptionPtr opt_msg_type(new LocalizedOption(Option::V4, + DHO_DHCP_MESSAGE_TYPE, + OptionBuffer(), + offset_msg_type)); + // Addition should be successful + ASSERT_NO_THROW(pkt->addOption(opt_merit)); + ASSERT_NO_THROW(pkt->addOption(opt_msg_type)); + + // Option fit to packet boundaries and offsets are valid, + // so this should unpack successfully. + ASSERT_TRUE(pkt->rawUnpack()); + + // At this point we should have updated options data (read from buffer). + // Let's try to retrieve them. + opt_merit = boost::dynamic_pointer_cast<LocalizedOption> + (pkt->getOption(DHO_MERIT_DUMP)); + opt_msg_type = boost::dynamic_pointer_cast<LocalizedOption> + (pkt->getOption(DHO_DHCP_MESSAGE_TYPE)); + ASSERT_TRUE(opt_merit); + ASSERT_TRUE(opt_msg_type); + + // Get first option payload. + OptionBuffer opt_merit_data = opt_merit->getData(); + + // Define reference data. + uint8_t buf_merit[] = { 20, 21, 22 }; + + // Validate first option data. + ASSERT_EQ(sizeof(buf_merit), opt_merit_data.size()); + EXPECT_TRUE(std::equal(opt_merit_data.begin(), + opt_merit_data.end(), + buf_merit)); + + // Get second option payload. + OptionBuffer opt_msg_type_data = opt_msg_type->getData(); + + // Expect one byte of message type payload. + ASSERT_EQ(1, opt_msg_type_data.size()); + EXPECT_EQ(1, opt_msg_type_data[0]); +} + +TEST_F(PerfPkt4Test, InvalidOptions) { + // Create new packet. + std::vector<uint8_t> buf = capture(); + boost::scoped_ptr<PerfPkt4> pkt1(new PerfPkt4(&buf[0], buf.size())); + + // Create option with invalid offset. + // This option is at offset 250 (not 251). + const size_t offset_merit = 251; + LocalizedOptionPtr opt_merit(new LocalizedOption(Option::V4, + DHO_MERIT_DUMP, + OptionBuffer(), + offset_merit)); + ASSERT_NO_THROW(pkt1->addOption(opt_merit)); + + cout << "Testing unpack of invalid options. " + << "This may produce spurious errors." << endl; + + // Unpack is expected to fail because it is supposed to read + // option type from buffer and match it with DHO_MERIT_DUMP. + // It will not match because option is shifted by on byte. + ASSERT_FALSE(pkt1->rawUnpack()); + + // Create another packet. + boost::scoped_ptr<PerfPkt4> pkt2(new PerfPkt4(&buf[0], buf.size())); + + // Create DHO_DHCP_MESSAGE_TYPE option that has the wrong offset. + // With this offset, option goes beyond packet size (268). + const size_t offset_msg_type = 266; + LocalizedOptionPtr opt_msg_type(new LocalizedOption(Option::V4, + DHO_DHCP_MESSAGE_TYPE, + OptionBuffer(1, 2), + offset_msg_type)); + // Adding option is expected to be successful because no + // offset validation takes place at this point. + ASSERT_NO_THROW(pkt2->addOption(opt_msg_type)); + + // This is expected to fail because option is out of bounds. + ASSERT_FALSE(pkt2->rawPack()); +} + +TEST_F(PerfPkt4Test, TruncatedPacket) { + // Get the whole packet and truncate it to 249 bytes. + std::vector<uint8_t> buf = capture(); + buf.resize(249); + boost::scoped_ptr<PerfPkt4> pkt(new PerfPkt4(&buf[0], buf.size())); + + // Option DHO_BOOT_SIZE is now truncated because whole packet + // is truncated. This option ends at 249 while last index of + // truncated packet is now 248. + const size_t offset_boot_filesize = 245; + LocalizedOptionPtr opt_boot_filesize(new LocalizedOption(Option::V4, + DHO_BOOT_SIZE, + OptionBuffer(3, 1), + offset_boot_filesize)); + ASSERT_NO_THROW(pkt->addOption(opt_boot_filesize)); + + cout << "Testing pack and unpack of options in truncated " + << "packet. This may produce spurious errors." << endl; + + // Both pack and unpack are expected to fail because + // added option is out of bounds. + EXPECT_FALSE(pkt->rawUnpack()); + EXPECT_FALSE(pkt->rawPack()); +} + +TEST_F(PerfPkt4Test, PackTransactionId) { + // Create dummy packet that consists of zeros. + std::vector<uint8_t> buf(268, 0); + + const size_t offset_transid[] = { 10, 265 }; + const uint32_t transid = 0x0102; + // Initialize transaction id 0x00000102 at offset 10. + boost::scoped_ptr<PerfPkt4> pkt1(new PerfPkt4(&buf[0], buf.size(), + offset_transid[0], + transid)); + + // Pack will inject transaction id at offset 10 into the + // packet buffer. + ASSERT_TRUE(pkt1->rawPack()); + + // Get packet's output buffer and make sure it has valid size. + util::OutputBuffer out_buf = pkt1->getBuffer(); + ASSERT_EQ(buf.size(), out_buf.getLength()); + const uint8_t *out_buf_data = + static_cast<const uint8_t*>(out_buf.getData()); + + // Initialize reference data for transaction id. + const uint8_t ref_data[] = { 0, 0, 1, 2 }; + + // Expect that reference transaction id matches what we have + // read from buffer. + EXPECT_EQ(0, memcmp(ref_data, out_buf_data + offset_transid[0], 4)); + + cout << "Testing pack with invalid transaction id offset. " + << "This may produce spurious errors" << endl; + + // Create packet with invalid transaction id offset. + // Packet length is 268, transaction id is 4 bytes long so last byte of + // transaction id is out of bounds. + boost::scoped_ptr<PerfPkt4> pkt2(new PerfPkt4(&buf[0], buf.size(), + offset_transid[1], + transid)); + EXPECT_FALSE(pkt2->rawPack()); +} + +TEST_F(PerfPkt4Test, UnpackTransactionId) { + // Initialize packet data, length 268, zeros only. + std::vector<uint8_t> in_data(268, 0); + + // Assume that transaction id is at offset 100. + // Fill 4 bytes at offset 100 with dummy transaction id. + for (uint8_t i = 100; i < 104; ++i) { + in_data[i] = i - 99; + } + + // Create packet from initialized buffer. + const size_t offset_transid[] = { 100, 270 }; + boost::scoped_ptr<PerfPkt4> pkt1(new PerfPkt4(&in_data[0], + in_data.size(), + offset_transid[0])); + ASSERT_TRUE(pkt1->rawUnpack()); + + // Get unpacked transaction id and compare with reference. + EXPECT_EQ(0x01020304, pkt1->getTransid()); + + // Create packet with transaction id at invalid offset. + boost::scoped_ptr<PerfPkt4> pkt2(new PerfPkt4(&in_data[0], + in_data.size(), + offset_transid[1])); + + cout << "Testing unpack of transaction id at invalid offset. " + << "This may produce spurious errors." << endl; + + // Unpack is supposed to fail because transaction id is at + // out of bounds offset. + EXPECT_FALSE(pkt2->rawUnpack()); +} + +TEST_F(PerfPkt4Test, Writes) { + // Initialize input buffer with 260 elements set to value 1. + dhcp::OptionBuffer in_data(260, 1); + // Initialize buffer to be used for write: 1,2,3,4,...,9 + dhcp::OptionBuffer write_buf(10); + for (size_t i = 0; i < write_buf.size(); ++i) { + write_buf[i] = i; + } + // Create packet from the input buffer. + const size_t transid_offset = 4; + boost::scoped_ptr<PerfPkt4> pkt1(new PerfPkt4(&in_data[0], + in_data.size(), + transid_offset)); + // Write numbers 4,5,6,7 to the packet's input buffer at position 10. + pkt1->writeAt(10, write_buf.begin() + 3, write_buf.begin() + 7); + // We have to pack data to output buffer here because Pkt4 provides no + // way to retrieve input buffer. If we pack data it will go to + // output buffer that has getter available. + ASSERT_TRUE(pkt1->rawPack()); + const util::OutputBuffer& out_buf = pkt1->getBuffer(); + ASSERT_EQ(in_data.size(), out_buf.getLength()); + // Verify that 4,5,6,7 has been written to the packet's buffer. + const char* out_data = static_cast<const char*>(out_buf.getData()); + EXPECT_TRUE(std::equal(write_buf.begin() + 3, write_buf.begin() + 7, + out_data + 10)); + // Write 1 octet (0x51) at position 10. + pkt1->writeValueAt<uint8_t>(10, 0x51); + ASSERT_TRUE(pkt1->rawPack()); + ASSERT_EQ(in_data.size(), pkt1->getBuffer().getLength()); + EXPECT_EQ(0x51, pkt1->getBuffer()[10]); + // Write 2 octets (0x5251) at position 20. + pkt1->writeValueAt<uint16_t>(20, 0x5251); + ASSERT_TRUE(pkt1->rawPack()); + ASSERT_EQ(in_data.size(), pkt1->getBuffer().getLength()); + EXPECT_EQ(0x52, pkt1->getBuffer()[20]); + EXPECT_EQ(0x51, pkt1->getBuffer()[21]); + // Write 4 octets (0x54535251) at position 30. + pkt1->writeValueAt<uint32_t>(30, 0x54535251); + ASSERT_TRUE(pkt1->rawPack()); + ASSERT_EQ(in_data.size(), pkt1->getBuffer().getLength()); + EXPECT_EQ(0x54, pkt1->getBuffer()[30]); + EXPECT_EQ(0x53, pkt1->getBuffer()[31]); + EXPECT_EQ(0x52, pkt1->getBuffer()[32]); + EXPECT_EQ(0x51, pkt1->getBuffer()[33]); +} + +} diff --git a/src/bin/perfdhcp/tests/perf_pkt6_unittest.cc b/src/bin/perfdhcp/tests/perf_pkt6_unittest.cc new file mode 100644 index 0000000..f4e5b41 --- /dev/null +++ b/src/bin/perfdhcp/tests/perf_pkt6_unittest.cc @@ -0,0 +1,324 @@ +// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> +#include <iostream> +#include <sstream> +#include <arpa/inet.h> +#include <gtest/gtest.h> + +#include <asiolink/io_address.h> +#include <dhcp/option.h> +#include <dhcp/dhcp6.h> + +#include <boost/scoped_ptr.hpp> + +#include "../localized_option.h" +#include "../perf_pkt6.h" + +using namespace std; +using namespace isc; +using namespace isc::dhcp; +using namespace isc::perfdhcp; + +typedef PerfPkt6::LocalizedOptionPtr LocalizedOptionPtr; + +namespace { + +class PerfPkt6Test : public ::testing::Test { +public: + PerfPkt6Test() { + } + + /// \brief Returns captured SOLICIT packet. + /// + /// Captured SOLICIT packet with transid=0x3d79fb and options: client-id, + /// in_na, dns-server, elapsed-time, option-request + /// This code was autogenerated + /// (see src/bin/dhcp6/tests/iface_mgr_unittest.c), + /// but we spent some time to make is less ugly than it used to be. + /// + /// \return pointer to Pkt6 that represents received SOLICIT + PerfPkt6* capture() { + uint8_t data[98]; + data[0] = 1; + data[1] = 1; data[2] = 2; data[3] = 3; data[4] = 0; + data[5] = 1; data[6] = 0; data[7] = 14; data[8] = 0; + data[9] = 1; data[10] = 0; data[11] = 1; data[12] = 21; + data[13] = 158; data[14] = 60; data[15] = 22; data[16] = 0; + data[17] = 30; data[18] = 140; data[19] = 155; data[20] = 115; + data[21] = 73; data[22] = 0; data[23] = 3; data[24] = 0; + data[25] = 40; data[26] = 0; data[27] = 0; data[28] = 0; + data[29] = 1; data[30] = 255; data[31] = 255; data[32] = 255; + data[33] = 255; data[34] = 255; data[35] = 255; data[36] = 255; + data[37] = 255; data[38] = 0; data[39] = 5; data[40] = 0; + data[41] = 24; data[42] = 32; data[43] = 1; data[44] = 13; + data[45] = 184; data[46] = 0; data[47] = 1; data[48] = 0; + data[49] = 0; data[50] = 0; data[51] = 0; data[52] = 0; + data[53] = 0; data[54] = 0; data[55] = 0; data[56] = 18; + data[57] = 52; data[58] = 255; data[59] = 255; data[60] = 255; + data[61] = 255; data[62] = 255; data[63] = 255; data[64] = 255; + data[65] = 255; data[66] = 0; data[67] = 23; data[68] = 0; + data[69] = 16; data[70] = 32; data[71] = 1; data[72] = 13; + data[73] = 184; data[74] = 0; data[75] = 1; data[76] = 0; + data[77] = 0; data[78] = 0; data[79] = 0; data[80] = 0; + data[81] = 0; data[82] = 0; data[83] = 0; data[84] = 221; + data[85] = 221; data[86] = 0; data[87] = 8; data[88] = 0; + data[89] = 2; data[90] = 0; data[91] = 100; data[92] = 0; + data[93] = 6; data[94] = 0; data[95] = 2; data[96] = 0; + data[97] = 23; + + PerfPkt6* pkt = new PerfPkt6(data, sizeof(data)); + + return (pkt); + } + + /// \brief Returns truncated SOLICIT packet. + /// + /// Returns truncated SOLICIT packet which will be used for + /// negative tests: e.g. pack options out of packet. + /// + /// \return pointer to Pkt6 that represents truncated SOLICIT + PerfPkt6* captureTruncated() { + uint8_t data[17]; + data[0] = 1; + data[1] = 1; data[2] = 2; data[3] = 3; data[4] = 0; + data[5] = 1; data[6] = 0; data[7] = 14; data[8] = 0; + data[9] = 1; data[10] = 0; data[11] = 1; data[12] = 21; + data[13] = 158; data[14] = 60; data[15] = 22; data[16] = 0; + + PerfPkt6* pkt = new PerfPkt6(data, sizeof(data)); + + return (pkt); + } + + +}; + +TEST_F(PerfPkt6Test, Constructor) { + // Data to be used to create packet. + uint8_t data[] = { 0, 1, 2, 3, 4, 5 }; + + // Test constructor to be used for incoming messages. + // Use default (1) offset value and don't specify transaction id. + boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, sizeof(data))); + EXPECT_EQ(sizeof(data), pkt1->data_.size()); + EXPECT_EQ(0, memcmp(&pkt1->data_[0], data, sizeof(data))); + EXPECT_EQ(1, pkt1->getTransidOffset()); + + // Test constructor to be used for outgoing messages. + // Use non-zero offset and specify transaction id. + const size_t offset_transid = 10; + const uint32_t transid = 0x010203; + boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data, sizeof(data), + offset_transid, transid)); + EXPECT_EQ(sizeof(data), pkt2->data_.size()); + EXPECT_EQ(0, memcmp(&pkt2->data_[0], data, sizeof(data))); + EXPECT_EQ(0x010203, pkt2->getTransid()); + EXPECT_EQ(10, pkt2->getTransidOffset()); +} + +TEST_F(PerfPkt6Test, RawPackUnpack) { + // Create first packet. + boost::scoped_ptr<PerfPkt6> pkt1(capture()); + + // Create some input buffers to initialize options. + uint8_t buf_elapsed_time[] = { 1, 1 }; + uint8_t buf_duid[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; + + // Create options. + const size_t offset_elapsed_time = 86; + OptionBuffer vec_elapsed_time(buf_elapsed_time, + buf_elapsed_time + sizeof(buf_elapsed_time)); + LocalizedOptionPtr pkt1_elapsed_time(new LocalizedOption(Option::V6, + D6O_ELAPSED_TIME, + vec_elapsed_time, + offset_elapsed_time)); + const size_t offset_duid = 4; + OptionBuffer vec_duid(buf_duid, buf_duid + sizeof(buf_duid)); + LocalizedOptionPtr pkt1_duid(new LocalizedOption(Option::V6, + D6O_CLIENTID, + vec_duid, + offset_duid)); + + // Add option to packet and create on-wire format from added options. + // Contents of options will override contents of packet buffer. + ASSERT_NO_THROW(pkt1->addOption(pkt1_elapsed_time)); + ASSERT_NO_THROW(pkt1->addOption(pkt1_duid)); + ASSERT_TRUE(pkt1->rawPack()); + + // Reset so as we can reuse them for another packet. + vec_elapsed_time.clear(); + vec_duid.clear(); + + // Get output buffer from packet 1 to create new packet + // that will be later validated. + util::OutputBuffer pkt1_output = pkt1->getBuffer(); + ASSERT_EQ(pkt1_output.getLength(), pkt1->data_.size()); + const uint8_t* pkt1_output_data = static_cast<const uint8_t*> + (pkt1_output.getData()); + boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(pkt1_output_data, + pkt1_output.getLength())); + + // Create objects specifying options offset in a packet. + // Offsets will inform pkt2 object where to read data from. + LocalizedOptionPtr pkt2_elapsed_time(new LocalizedOption(Option::V6, + D6O_ELAPSED_TIME, + vec_elapsed_time, + offset_elapsed_time)); + LocalizedOptionPtr pkt2_duid(new LocalizedOption(Option::V6, + D6O_CLIENTID, + vec_duid, + offset_duid)); + // Add options to packet to pass their offsets. + pkt2->addOption(pkt2_elapsed_time); + pkt2->addOption(pkt2_duid); + + // Unpack: get relevant parts of buffer data into option objects. + ASSERT_TRUE(pkt2->rawUnpack()); + + // Once option data is stored in options objects we pull it out. + pkt2_elapsed_time = boost::dynamic_pointer_cast<LocalizedOption> + (pkt2->getOption(D6O_ELAPSED_TIME)); + pkt2_duid = boost::dynamic_pointer_cast<LocalizedOption> + (pkt2->getOption(D6O_CLIENTID)); + + // Check if options are present. They have to be there since + // we have added them ourselfs. + ASSERT_TRUE(pkt2_elapsed_time); + ASSERT_TRUE(pkt2_duid); + + // Expecting option contents be the same as original. + OptionBuffer pkt2_elapsed_time_data = pkt2_elapsed_time->getData(); + OptionBuffer pkt2_duid_data = pkt2_duid->getData(); + EXPECT_EQ(0x0101, pkt2_elapsed_time->getUint16()); + EXPECT_TRUE(std::equal(pkt2_duid_data.begin(), + pkt2_duid_data.end(), + buf_duid)); +} + +TEST_F(PerfPkt6Test, InvalidOptions) { + // Create packet. + boost::scoped_ptr<PerfPkt6> pkt1(capture()); + OptionBuffer vec_server_id; + vec_server_id.resize(10); + // Testing invalid offset of the option (greater than packet size) + const size_t offset_serverid[] = { 150, 85 }; + LocalizedOptionPtr pkt1_serverid(new LocalizedOption(Option::V6, + D6O_SERVERID, + vec_server_id, + offset_serverid[0])); + pkt1->addOption(pkt1_serverid); + // Pack has to fail due to invalid offset. + EXPECT_FALSE(pkt1->rawPack()); + + // Create packet. + boost::scoped_ptr<PerfPkt6> pkt2(capture()); + // Testing offset of the option (lower than packet size but + // tail of the option out of bounds). + LocalizedOptionPtr pkt2_serverid(new LocalizedOption(Option::V6, + D6O_SERVERID, + vec_server_id, + offset_serverid[1])); + pkt2->addOption(pkt2_serverid); + // Pack must fail due to invalid offset. + EXPECT_FALSE(pkt2->rawPack()); +} + + +TEST_F(PerfPkt6Test, TruncatedPacket) { + cout << "Testing parsing options from truncated packet." + << "This may produce spurious errors" << endl; + + // Create truncated (in the middle of duid options) + boost::scoped_ptr<PerfPkt6> pkt1(captureTruncated()); + OptionBuffer vec_duid; + vec_duid.resize(30); + const size_t offset_duid = 4; + LocalizedOptionPtr pkt1_duid(new LocalizedOption(Option::V6, + D6O_CLIENTID, + vec_duid, + offset_duid)); + pkt1->addOption(pkt1_duid); + // Pack/unpack must fail because length of the option read from buffer + // will extend over the actual packet length. + EXPECT_FALSE(pkt1->rawUnpack()); + EXPECT_FALSE(pkt1->rawPack()); +} + +TEST_F(PerfPkt6Test, PackTransactionId) { + uint8_t data[100]; + memset(&data, 0, sizeof(data)); + + const size_t offset_transid[] = { 50, 100 }; + const uint32_t transid = 0x010203; + + // Create dummy packet that is simply filled with zeros. + boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, + sizeof(data), + offset_transid[0], + transid)); + + // Reference data are non zero so we can detect them in dummy packet. + uint8_t ref_data[3] = { 1, 2, 3 }; + + // This will store given transaction id in the packet data at + // offset of 50. + ASSERT_TRUE(pkt1->rawPack()); + + // Get the output buffer so we can validate it. + util::OutputBuffer out_buf = pkt1->getBuffer(); + ASSERT_EQ(sizeof(data), out_buf.getLength()); + const uint8_t *out_buf_data = static_cast<const uint8_t*> + (out_buf.getData()); + + // Try to make clang static analyzer happy. + ASSERT_LE(offset_transid[0], out_buf.getLength()); + + // Validate transaction id. + EXPECT_EQ(0, memcmp(ref_data, out_buf_data + offset_transid[0], 3)); + + + // Out of bounds transaction id offset. + boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data, + sizeof(data), + offset_transid[1], + transid)); + cout << "Testing out of bounds offset. " + "This may produce spurious errors ..." << endl; + EXPECT_FALSE(pkt2->rawPack()); +} + +TEST_F(PerfPkt6Test, UnpackTransactionId) { + // Initialize data for dummy packet (zeros only). + uint8_t data[100] = { 0 }; + + // Generate transaction id = 0x010203 and inject at offset = 50. + for (uint8_t i = 50; i < 53; ++i) { + data[i] = i - 49; + } + // Create packet and point out that transaction id is at offset 50. + const size_t offset_transid[] = { 50, 300 }; + boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, + sizeof(data), + offset_transid[0])); + + // Get transaction id out of buffer and store in class member. + ASSERT_TRUE(pkt1->rawUnpack()); + // Test value of transaction id. + EXPECT_EQ(0x010203, pkt1->getTransid()); + + // Out of bounds transaction id offset. + boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data, + sizeof(data), + offset_transid[1])); + cout << "Testing out of bounds offset. " + "This may produce spurious errors ..." << endl; + EXPECT_FALSE(pkt2->rawUnpack()); + +} + +} diff --git a/src/bin/perfdhcp/tests/perf_socket_unittest.cc b/src/bin/perfdhcp/tests/perf_socket_unittest.cc new file mode 100644 index 0000000..39a2db9 --- /dev/null +++ b/src/bin/perfdhcp/tests/perf_socket_unittest.cc @@ -0,0 +1,58 @@ +// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include "command_options_helper.h" +#include "../perf_socket.h" + +#include <asiolink/io_address.h> +#include <exceptions/exceptions.h> +#include <dhcp/dhcp4.h> +#include <dhcp/pkt4.h> +#include <dhcp/iface_mgr.h> + +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/foreach.hpp> + +#include <algorithm> +#include <cstddef> +#include <stdint.h> +#include <string> +#include <fstream> +#include <gtest/gtest.h> + +using namespace std; +using namespace boost::posix_time; +using namespace isc; +using namespace isc::dhcp; +using namespace isc::perfdhcp; + + +/// \brief Test Fixture Class +/// +/// This test fixture class is used to perform +/// unit tests on perfdhcp PerfSocketTest class. +class PerfSocketTest : public virtual ::testing::Test +{ +public: + PerfSocketTest() { } +}; + + +TEST_F(PerfSocketTest, WrongCommandOptions) { + // Check if incorrect command options are casing failure during + // socket setup. + CommandOptions opt; + + // make sure we catch -6 paired with v4 address + CommandOptionsHelper::process(opt, "perfdhcp -l 127.0.0.1 -6 192.168.1.1"); + EXPECT_THROW(PerfSocket sock(opt), isc::InvalidParameter); + + // make sure we catch -4 paired with v6 address + CommandOptionsHelper::process(opt, "perfdhcp -l 127.0.0.1 -4 ff02::1:2"); + EXPECT_THROW(PerfSocket sock(opt), isc::InvalidParameter); +} diff --git a/src/bin/perfdhcp/tests/random_number_generator_unittest.cc b/src/bin/perfdhcp/tests/random_number_generator_unittest.cc new file mode 100644 index 0000000..58da955 --- /dev/null +++ b/src/bin/perfdhcp/tests/random_number_generator_unittest.cc @@ -0,0 +1,296 @@ +// Copyright (C) 2010-2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <perfdhcp/random_number_generator.h> + +#include <gtest/gtest.h> +#include <boost/shared_ptr.hpp> + +#include <iostream> + +using namespace isc; +using namespace isc::perfdhcp; +using namespace std; + +/// \brief Test Fixture Class for uniform random number generator +/// +/// The hard part for this test is how to test that the number is random? +/// and how to test that the number is uniformly distributed? +/// Or maybe we can trust the boost implementation +class UniformRandomIntegerGeneratorTest : public ::testing::Test { +public: + UniformRandomIntegerGeneratorTest(): + gen_(min_, max_) + { + } + virtual ~UniformRandomIntegerGeneratorTest(){} + + int gen() { return (gen_()); } + int max() const { return (max_); } + int min() const { return (min_); } + +private: + UniformRandomIntegerGenerator gen_; + + const static int min_ = 1; + const static int max_ = 10; +}; + +// Some validation tests will incur performance penalty, so the tests are +// made only in "debug" version with assert(). But if NDEBUG is defined +// the tests will be failed since assert() is non-op in non-debug version. +// The "#ifndef NDEBUG" is added to make the tests be performed only in +// non-debug environment. +// Note: the death test is not supported by all platforms. We need to +// compile tests using it selectively. +#if !defined(NDEBUG) +// Test of the constructor +TEST_F(UniformRandomIntegerGeneratorTest, Constructor) { + // The range must be min<=max + ASSERT_THROW(UniformRandomIntegerGenerator(3, 2), InvalidLimits); +} +#endif + +// Test of the generated integers are in the range [min, max] +TEST_F(UniformRandomIntegerGeneratorTest, IntegerRange) { + vector<int> numbers; + + // Generate a lot of random integers + for (int i = 0; i < max()*10; ++i) { + numbers.push_back(gen()); + } + + // Remove the duplicated values + sort(numbers.begin(), numbers.end()); + vector<int>::iterator it = unique(numbers.begin(), numbers.end()); + + // make sure the numbers are in range [min, max] + ASSERT_EQ(it - numbers.begin(), max() - min() + 1); +} + +/// \brief Test Fixture Class for weighted random number generator +class WeightedRandomIntegerGeneratorTest : public ::testing::Test { +public: + WeightedRandomIntegerGeneratorTest() + { } + + virtual ~WeightedRandomIntegerGeneratorTest() + { } +}; + +// Test of the weighted random number generator constructor +TEST_F(WeightedRandomIntegerGeneratorTest, Constructor) { + vector<double> probabilities; + + // If no probabilities is provided, the smallest integer will always + // be generated + WeightedRandomIntegerGenerator gen(probabilities, 123); + for (int i = 0; i < 100; ++i) { + ASSERT_EQ(gen(), 123); + } + +/// Some validation tests will incur performance penalty, so the tests are +/// made only in "debug" version with assert(). But if NDEBUG is defined +/// the tests will be failed since assert() is non-op in non-debug version. +/// The "#ifndef NDEBUG" is added to make the tests be performed only in +/// non-debug environment. +#if !defined(NDEBUG) + //The probability must be >= 0 + probabilities.push_back(-0.1); + probabilities.push_back(1.1); + ASSERT_THROW(WeightedRandomIntegerGenerator gen2(probabilities), + InvalidProbValue); + + //The probability must be <= 1.0 + probabilities.clear(); + probabilities.push_back(0.1); + probabilities.push_back(1.1); + ASSERT_THROW(WeightedRandomIntegerGenerator gen3(probabilities), + InvalidProbValue); + + //The sum must be equal to 1.0 + probabilities.clear(); + probabilities.push_back(0.2); + probabilities.push_back(0.9); + ASSERT_THROW(WeightedRandomIntegerGenerator gen4(probabilities), SumNotOne); + + //The sum must be equal to 1.0 + probabilities.clear(); + probabilities.push_back(0.3); + probabilities.push_back(0.2); + probabilities.push_back(0.1); + ASSERT_THROW(WeightedRandomIntegerGenerator gen5(probabilities), SumNotOne); +#endif +} + +// Test the randomization of the generator +TEST_F(WeightedRandomIntegerGeneratorTest, WeightedRandomization) { + const int repeats = 100000; + // We repeat the simulation for N=repeats times + // for each probability p, its average is mu = N*p + // variance sigma^2 = N * p * (1-p) + // sigma = sqrt(N*2/9) + // we should make sure that mu - 4sigma < count < mu + 4sigma + // which means for 99.99366% of the time this should be true + { + double p = 0.5; + vector<double> probabilities; + probabilities.push_back(p); + probabilities.push_back(p); + + // Uniformly generated integers + WeightedRandomIntegerGenerator gen(probabilities); + int c1 = 0; + int c2 = 0; + for (int i = 0; i < repeats; ++i){ + int n = gen(); + if (n == 0) { + ++c1; + } else if (n == 1) { + ++c2; + } + } + double mu = repeats * p; + double sigma = sqrt(repeats * p * (1 - p)); + ASSERT_TRUE(fabs(c1 - mu) < 4*sigma); + ASSERT_TRUE(fabs(c2 - mu) < 4*sigma); + } + + { + vector<double> probabilities; + int c1 = 0; + int c2 = 0; + double p1 = 0.2; + double p2 = 0.8; + probabilities.push_back(p1); + probabilities.push_back(p2); + WeightedRandomIntegerGenerator gen(probabilities); + for (int i = 0; i < repeats; ++i) { + int n = gen(); + if (n == 0) { + ++c1; + } else if (n == 1) { + ++c2; + } + } + double mu1 = repeats * p1; + double mu2 = repeats * p2; + double sigma1 = sqrt(repeats * p1 * (1 - p1)); + double sigma2 = sqrt(repeats * p2 * (1 - p2)); + ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1); + ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2); + } + + { + vector<double> probabilities; + int c1 = 0; + int c2 = 0; + double p1 = 0.8; + double p2 = 0.2; + probabilities.push_back(p1); + probabilities.push_back(p2); + WeightedRandomIntegerGenerator gen(probabilities); + for (int i = 0; i < repeats; ++i) { + int n = gen(); + if (n == 0) { + ++c1; + } else if (n == 1) { + ++c2; + } + } + double mu1 = repeats * p1; + double mu2 = repeats * p2; + double sigma1 = sqrt(repeats * p1 * (1 - p1)); + double sigma2 = sqrt(repeats * p2 * (1 - p2)); + ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1); + ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2); + } + + { + vector<double> probabilities; + int c1 = 0; + int c2 = 0; + int c3 = 0; + double p1 = 0.5; + double p2 = 0.25; + double p3 = 0.25; + probabilities.push_back(p1); + probabilities.push_back(p2); + probabilities.push_back(p3); + WeightedRandomIntegerGenerator gen(probabilities); + for (int i = 0; i < repeats; ++i){ + int n = gen(); + if (n == 0) { + ++c1; + } else if (n == 1) { + ++c2; + } else if (n == 2) { + ++c3; + } + } + double mu1 = repeats * p1; + double mu2 = repeats * p2; + double mu3 = repeats * p3; + double sigma1 = sqrt(repeats * p1 * (1 - p1)); + double sigma2 = sqrt(repeats * p2 * (1 - p2)); + double sigma3 = sqrt(repeats * p3 * (1 - p3)); + ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1); + ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2); + ASSERT_TRUE(fabs(c3 - mu3) < 4*sigma3); + } +} + +// Test the reset function of generator +TEST_F(WeightedRandomIntegerGeneratorTest, ResetProbabilities) { + const int repeats = 100000; + vector<double> probabilities; + int c1 = 0; + int c2 = 0; + double p1 = 0.8; + double p2 = 0.2; + probabilities.push_back(p1); + probabilities.push_back(p2); + WeightedRandomIntegerGenerator gen(probabilities); + for (int i = 0; i < repeats; ++i) { + int n = gen(); + if (n == 0) { + ++c1; + } else if (n == 1) { + ++c2; + } + } + double mu1 = repeats * p1; + double mu2 = repeats * p2; + double sigma1 = sqrt(repeats * p1 * (1 - p1)); + double sigma2 = sqrt(repeats * p2 * (1 - p2)); + ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1); + ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2); + + // Reset the probabilities + probabilities.clear(); + c1 = c2 = 0; + p1 = 0.2; + p2 = 0.8; + probabilities.push_back(p1); + probabilities.push_back(p2); + gen.reset(probabilities); + for (int i = 0; i < repeats; ++i) { + int n = gen(); + if (n == 0) { + ++c1; + } else if (n == 1) { + ++c2; + } + } + mu1 = repeats * p1; + mu2 = repeats * p2; + sigma1 = sqrt(repeats * p1 * (1 - p1)); + sigma2 = sqrt(repeats * p2 * (1 - p2)); + ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1); + ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2); +} diff --git a/src/bin/perfdhcp/tests/rate_control_unittest.cc b/src/bin/perfdhcp/tests/rate_control_unittest.cc new file mode 100644 index 0000000..5619fd3 --- /dev/null +++ b/src/bin/perfdhcp/tests/rate_control_unittest.cc @@ -0,0 +1,105 @@ +// Copyright (C) 2013-2019 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <exceptions/exceptions.h> +#include "rate_control.h" +#include <gtest/gtest.h> + + +using namespace isc; +using namespace isc::perfdhcp; + +/// \brief A class which exposes protected methods and members of the +/// RateControl class (under test). +class NakedRateControl : public RateControl { +public: + + /// \brief Default constructor. + NakedRateControl() + : RateControl() { + } + + /// \brief Constructor which sets up the rate. + /// + /// \param rate A rate at which messages are sent. + /// maximal number of messages sent in one chunk. + NakedRateControl(const int rate) + : RateControl(rate) { + } + + using RateControl::currentTime; + using RateControl::start_time_; +}; + +// Test default constructor. +TEST(RateControl, constructorDefault) { + NakedRateControl rc; + EXPECT_EQ(0, rc.getRate()); +} + +// Test the constructor which sets the rate. +TEST(RateControl, constructor) { + // Call the constructor and verify that it sets the appropriate + // values. + NakedRateControl rc1(3); + EXPECT_EQ(3, rc1.getRate()); + + // Call the constructor again and make sure that different values + // will be set correctly. + NakedRateControl rc2(5); + EXPECT_EQ(5, rc2.getRate()); +} + +// Check the rate accessor. +TEST(RateControl, getRate) { + RateControl rc; + ASSERT_EQ(0, rc.getRate()); + rc.setRate(5); + ASSERT_EQ(5, rc.getRate()); + rc.setRate(10); + EXPECT_EQ(10, rc.getRate()); +} + +// Check that the function returns the number of messages to be sent "now" +// correctly. +// @todo Possibly extend this test to cover more complex scenarios. Note that +// it is quite hard to fully test this function as its behaviour strongly +// depends on time. +TEST(RateControl, getOutboundMessageCount) { + // Test that the number of outbound messages is correctly defined by the + // rate. + NakedRateControl rc(2); + + // The first call to getOutboundMessageCount always returns 0 as there is + // no good estimate at the beginning how many packets to send. + uint64_t count = 0; + ASSERT_NO_THROW(count = rc.getOutboundMessageCount()); + EXPECT_EQ(count, 1); + + // After a given amount of time number of packets to send should + // allow to catch up with requested rate, ie for rate 2pks/s after 1500ms + // it should send 2 pkts/s * 1.5s = about 2 pkts. + // To simulate 1500ms lets get back start time by 1500ms. + rc.start_time_ -= boost::posix_time::milliseconds(1500); + ASSERT_NO_THROW(count = rc.getOutboundMessageCount()); + EXPECT_EQ(count, 2); + + // If elapsed time is big then a big number of packets would need to be sent. + // But the pkts number is capped to 3. Check it. + rc.start_time_ -= boost::posix_time::milliseconds(10000); + ASSERT_NO_THROW(count = rc.getOutboundMessageCount()); + EXPECT_EQ(count, 3); +} + +// Test the rate modifier for valid and invalid rate values. +TEST(RateControl, setRate) { + NakedRateControl rc; + EXPECT_NO_THROW(rc.setRate(1)); + EXPECT_NO_THROW(rc.setRate(0)); + EXPECT_THROW(rc.setRate(-1), isc::BadValue); +} diff --git a/src/bin/perfdhcp/tests/receiver_unittest.cc b/src/bin/perfdhcp/tests/receiver_unittest.cc new file mode 100644 index 0000000..1a1cb68 --- /dev/null +++ b/src/bin/perfdhcp/tests/receiver_unittest.cc @@ -0,0 +1,116 @@ +// Copyright (C) 2018-2019 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include "command_options_helper.h" + +#include <dhcp/iface_mgr.h> + + +#include <exceptions/exceptions.h> +#include "receiver.h" +#include <gtest/gtest.h> + + +using namespace isc; +using namespace isc::dhcp; +using namespace isc::perfdhcp; + + +/// \brief FakeReceiverPerfSocket class that mocks PerfSocket. +/// +/// It stubs send and receive operations and collects statistics. +class FakeReceiverPerfSocket: public BasePerfSocket { +public: + /// \brief Default constructor for FakeReceiverPerfSocket. + FakeReceiverPerfSocket() : + iface_(boost::make_shared<Iface>("fake", 0)), + sent_cnt_(0), + recv_cnt_(0) {}; + + IfacePtr iface_; ///< Local fake interface. + + int sent_cnt_; ///< Counter of sent packets + int recv_cnt_; ///< Counter of received packets. + + /// \brief Simulate receiving DHCPv4 packet. + virtual dhcp::Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec) override { + (void)timeout_sec; // silence compile 'unused parameter' warning; + (void)timeout_usec; // silence compile 'unused parameter' warning; + recv_cnt_++; + // slow down receiving as receiver calls it in a loop thousands of time + // if null is returned + usleep(50); + return(dhcp::Pkt4Ptr()); + }; + + /// \brief Simulate receiving DHCPv6 packet. + virtual dhcp::Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec) override { + (void)timeout_sec; // silence compile 'unused parameter' warning; + (void)timeout_usec; // silence compile 'unused parameter' warning; + recv_cnt_++; + return(dhcp::Pkt6Ptr()); + }; + + /// \brief Simulate sending DHCPv4 packet. + virtual bool send(const dhcp::Pkt4Ptr& pkt) override { + sent_cnt_++; + pkt->updateTimestamp(); + return true; + }; + + /// \brief Simulate sending DHCPv6 packet. + virtual bool send(const dhcp::Pkt6Ptr& pkt) override { + sent_cnt_++; + pkt->updateTimestamp(); + return true; + }; + + /// \brief Override getting interface. + virtual IfacePtr getIface() override { return iface_; } + + void reset() { + sent_cnt_ = 0; + recv_cnt_ = 0; + } +}; + + +TEST(Receiver, singleThreaded) { + CommandOptions opt; + CommandOptionsHelper::process(opt, "perfdhcp -g single -l 127.0.0.1 all"); + ASSERT_TRUE(opt.isSingleThreaded()); + + FakeReceiverPerfSocket socket; + Receiver receiver(socket, opt.isSingleThreaded(), opt.getIpVersion()); + + ASSERT_NO_THROW(receiver.start()); + + auto pkt = receiver.getPkt(); + + EXPECT_EQ(pkt, nullptr); + + ASSERT_NO_THROW(receiver.stop()); +} + + +TEST(Receiver, multiThreaded) { + CommandOptions opt; + CommandOptionsHelper::process(opt, "perfdhcp -g multi -l 127.0.0.1 all"); + ASSERT_FALSE(opt.isSingleThreaded()); + + FakeReceiverPerfSocket socket; + Receiver receiver(socket, opt.isSingleThreaded(), opt.getIpVersion()); + + ASSERT_NO_THROW(receiver.start()); + + auto pkt = receiver.getPkt(); + + EXPECT_EQ(pkt, nullptr); + + ASSERT_NO_THROW(receiver.stop()); +} diff --git a/src/bin/perfdhcp/tests/run_unittests.cc b/src/bin/perfdhcp/tests/run_unittests.cc new file mode 100644 index 0000000..628f79d --- /dev/null +++ b/src/bin/perfdhcp/tests/run_unittests.cc @@ -0,0 +1,17 @@ +// Copyright (C) 2009-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <gtest/gtest.h> +#include <util/unittests/run_all.h> + +int +main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + + return (isc::util::unittests::run_all()); +} diff --git a/src/bin/perfdhcp/tests/stats_mgr_unittest.cc b/src/bin/perfdhcp/tests/stats_mgr_unittest.cc new file mode 100644 index 0000000..54253d5 --- /dev/null +++ b/src/bin/perfdhcp/tests/stats_mgr_unittest.cc @@ -0,0 +1,598 @@ +// Copyright (C) 2012-2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include "command_options_helper.h" + +#include <perfdhcp/stats_mgr.h> + +#include <exceptions/exceptions.h> +#include <dhcp/dhcp4.h> +#include <dhcp/dhcp6.h> +#include <dhcp/pkt4.h> +#include <dhcp/pkt6.h> + +#include <gtest/gtest.h> + +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/scoped_ptr.hpp> +#include <boost/shared_ptr.hpp> + +using namespace std; +using namespace isc; +using namespace isc::dhcp; +using namespace isc::perfdhcp; + +namespace { + +const uint32_t common_transid = 123; + +/// @brief Number of packets to be used for testing packets collecting. +const size_t TEST_COLLECTED_PKT_NUM = 10; + +/// @brief DHCPv4 packet with modifiable internal values. +/// +/// Currently the only additional modifiable value is a packet +/// timestamp. +class Pkt4Modifiable : public Pkt4 { +public: + + /// @brief Constructor. + /// + /// @param msg_type DHCPv4 message type. + /// @param transid Transaction id. + Pkt4Modifiable(const uint8_t msg_type, const uint32_t transid) + : Pkt4(msg_type, transid) { + } + + /// @brief Modifies packet timestamp. + /// + /// @param delta Number of seconds to be added to the current + /// packet time. If this number is negative, the new timestamp + /// will point to earlier time than the original timestamp. + void modifyTimestamp(const long delta) { + timestamp_ += boost::posix_time::seconds(delta); + } +}; + +/// @brief Pointer to the Pkt4Modifiable. +typedef boost::shared_ptr<Pkt4Modifiable> Pkt4ModifiablePtr; + +class StatsMgrTest : public ::testing::Test { +public: + StatsMgrTest() { + } + + /// \brief Create DHCPv4 packet. + /// + /// Method creates DHCPv4 packet and updates its timestamp. + /// + /// \param msg_type DHCPv4 message type. + /// \param transid transaction id for the packet. + /// \return DHCPv4 packet. + Pkt4Modifiable* createPacket4(const uint8_t msg_type, + const uint32_t transid) { + Pkt4Modifiable* pkt = new Pkt4Modifiable(msg_type, transid); + // Packet timestamp is normally updated by interface + // manager on packets reception or send. Unit tests + // do not use interface manager so we need to do it + // ourselves. + pkt->updateTimestamp(); + return (pkt); + } + + /// \brief Create DHCPv6 packet. + /// + /// Method creates DHCPv6 packet and updates its timestamp. + /// + /// \param msg_type DHCPv6 message type. + /// \param transid transaction id. + /// \return DHCPv6 packet. + Pkt6* createPacket6(const uint8_t msg_type, + const uint32_t transid) { + Pkt6* pkt = new Pkt6(msg_type, transid); + // Packet timestamp is normally updated by interface + // manager on packets reception or send. Unit tests + // do not use interface manager so we need to do it + // ourselves. + pkt->updateTimestamp(); + return pkt; + } + + /// \brief Pass multiple DHCPv6 packets to Statistics Manager. + /// + /// 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. + /// \param num_packets packets to be passed to Statistics Manager. + /// \param receive simulated packets are received (if true) + /// or sent (if false) + void passMultiplePackets6(const boost::shared_ptr<StatsMgr> stats_mgr, + ExchangeType xchg_type, + const uint8_t packet_type, + const int num_packets, + const bool receive = false) { + for (int i = 0; i < num_packets; ++i) { + boost::shared_ptr<Pkt6> + packet(createPacket6(packet_type, i)); + + if (receive) { + ASSERT_NO_THROW( + stats_mgr->passRcvdPacket(xchg_type, packet); + ); + } else { + ASSERT_NO_THROW( + stats_mgr->passSentPacket(xchg_type, packet) + ); + } + } + } + + /// \brief Simulate DHCPv4 DISCOVER-OFFER with delay. + /// + /// Method simulates DHCPv4 DISCOVER-OFFER exchange. The OFFER packet + /// creation is delayed by the specified number of seconds. This imposes + /// different packet timestamps and affects delay counters in Statistics + /// Manager. + /// + /// \param stats_mgr Statistics Manager instance. + /// \param delay delay in seconds between DISCOVER and OFFER packets. + void passDOPacketsWithDelay(const boost::shared_ptr<StatsMgr> stats_mgr, + unsigned int delay, + uint32_t transid) { + boost::shared_ptr<Pkt4> sent_packet(createPacket4(DHCPDISCOVER, + transid)); + ASSERT_NO_THROW( + stats_mgr->passSentPacket(ExchangeType::DO, sent_packet) + ); + + // Simulate time difference by changing time of sent packet + auto ts = sent_packet->getTimestamp() - boost::posix_time::seconds(delay); + sent_packet->setTimestamp(ts); + + boost::shared_ptr<Pkt4> rcvd_packet(createPacket4(DHCPOFFER, + transid)); + ASSERT_NO_THROW( + stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet); + ); + + // Calculate period between packets. + boost::posix_time::ptime sent_time = sent_packet->getTimestamp(); + boost::posix_time::ptime rcvd_time = rcvd_packet->getTimestamp(); + + ASSERT_FALSE(sent_time.is_not_a_date_time()); + ASSERT_FALSE(rcvd_time.is_not_a_date_time()); + } + + /// @brief This test verifies that timed out packets are collected. + /// + /// @param transid_index Index in the table of transaction ids which + /// points to the transaction id to be selected for the DHCPOFFER. + void testSendReceiveCollected(const size_t transid_index) { + CommandOptions opt; + boost::scoped_ptr<StatsMgr> stats_mgr(new StatsMgr(opt)); + // The second parameter indicates that transactions older than + // 2 seconds should be removed and respective packets collected. + stats_mgr->addExchangeStats(ExchangeType::DO, 2); + + // Transaction ids of packets to be sent. All transaction ids + // belong to the same bucket (match the transid & 1023 hashing + // function). + uint32_t transid[TEST_COLLECTED_PKT_NUM] = + { 1, 1025, 2049, 3073, 4097, 5121, 6145, 7169, 8193, 9217 }; + + // Simulate sending a number of packets. + for (unsigned int i = 0; i < TEST_COLLECTED_PKT_NUM; ++i) { + Pkt4ModifiablePtr sent_packet(createPacket4(DHCPDISCOVER, + transid[i])); + // For packets with low indexes we set the timestamps to + // 10s in the past. When DHCPOFFER is processed, the + // packets with timestamps older than 2s should be collected. + if (i < TEST_COLLECTED_PKT_NUM / 2) { + sent_packet->modifyTimestamp(-10); + } + ASSERT_NO_THROW( + stats_mgr->passSentPacket(ExchangeType::DO, sent_packet) + ) << "failure for transaction id " << transid[i]; + } + + // Create a server response for one of the packets sent. + Pkt4ModifiablePtr rcvd_packet(createPacket4(DHCPOFFER, + transid[transid_index])); + ASSERT_NO_THROW( + stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet); + ); + + // There is exactly one case (transaction id) for which perfdhcp + // will find a packet using ordered lookup. In this case, no + // packets will be collected. Otherwise, for any unordered lookup + // all packets from a bucket should be collected. + if (stats_mgr->getUnorderedLookups(ExchangeType::DO) > 0) { + // All packets in the bucket having transaction id + // index below TEST_COLLECTED_PKT_NUM / 2 should be removed. + EXPECT_EQ(TEST_COLLECTED_PKT_NUM / 2, + stats_mgr->getCollectedNum(ExchangeType::DO)); + } + + // Make sure that we can still use the StatsMgr. It is possible + // that the pointer to 'next sent' packet was invalidated + // during packet removal. + for (unsigned int i = 0; i < TEST_COLLECTED_PKT_NUM; ++i) { + // Increase transaction ids by 1 so as they don't duplicate + // with transaction ids of already sent packets. + Pkt4ModifiablePtr sent_packet(createPacket4(DHCPDISCOVER, + transid[i] + 1)); + Pkt4ModifiablePtr rcvd_packet(createPacket4(DHCPOFFER, + transid[i] + 1)); + ASSERT_NO_THROW( + stats_mgr->passSentPacket(ExchangeType::DO, sent_packet) + ) << "failure for transaction id " << transid[i]; + + ASSERT_NO_THROW( + stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet); + ) << "failure for transaction id " << transid[i]; + } + + // We should have processed TEST_COLLECTED_PKT_NUM but it is possible + // that one of them we couldn't match (orphan packet), because + // the matched packet had to be collected because of the transaction + // timeout. Therefore, we have to count both received packets and + // orphans. + EXPECT_EQ(TEST_COLLECTED_PKT_NUM + 1, + stats_mgr->getRcvdPacketsNum(ExchangeType::DO) + + stats_mgr->getOrphans(ExchangeType::DO)); + } +}; + +TEST_F(StatsMgrTest, Constructor) { + CommandOptions opt; + boost::scoped_ptr<StatsMgr> stats_mgr(new StatsMgr(opt)); + stats_mgr->addExchangeStats(ExchangeType::DO); + EXPECT_DOUBLE_EQ( + std::numeric_limits<double>::max(), + stats_mgr->getMinDelay(ExchangeType::DO) + ); + EXPECT_DOUBLE_EQ(0, stats_mgr->getMaxDelay(ExchangeType::DO)); + EXPECT_EQ(0, stats_mgr->getOrphans(ExchangeType::DO)); + EXPECT_EQ(0, stats_mgr->getOrderedLookups(ExchangeType::DO)); + EXPECT_EQ(0, stats_mgr->getUnorderedLookups(ExchangeType::DO)); + EXPECT_EQ(0, stats_mgr->getSentPacketsNum(ExchangeType::DO)); + EXPECT_EQ(0, stats_mgr->getRcvdPacketsNum(ExchangeType::DO)); + EXPECT_EQ(0, stats_mgr->getCollectedNum(ExchangeType::DO)); + + EXPECT_THROW(stats_mgr->getAvgDelay(ExchangeType::DO), InvalidOperation); + EXPECT_THROW(stats_mgr->getStdDevDelay(ExchangeType::DO), + InvalidOperation); + EXPECT_THROW(stats_mgr->getAvgUnorderedLookupSetSize(ExchangeType::DO), + InvalidOperation); +} + +TEST_F(StatsMgrTest, Exchange) { + CommandOptions opt; + boost::scoped_ptr<StatsMgr> stats_mgr(new StatsMgr(opt)); + boost::shared_ptr<Pkt4> sent_packet(createPacket4(DHCPDISCOVER, + common_transid)); + boost::shared_ptr<Pkt4> rcvd_packet(createPacket4(DHCPOFFER, + common_transid)); + // This is expected to throw because XCHG_DO was not yet + // added to Stats Manager for tracking. + ASSERT_FALSE(stats_mgr->hasExchangeStats(ExchangeType::DO)); + ASSERT_FALSE(stats_mgr->hasExchangeStats(ExchangeType::RA)); + EXPECT_THROW( + stats_mgr->passSentPacket(ExchangeType::DO, sent_packet), + BadValue + ); + EXPECT_THROW( + stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet), + BadValue + ); + + + // Adding DISCOVER-OFFER exchanges to be tracked by Stats Manager. + stats_mgr->addExchangeStats(ExchangeType::DO); + ASSERT_TRUE(stats_mgr->hasExchangeStats(ExchangeType::DO)); + ASSERT_FALSE(stats_mgr->hasExchangeStats(ExchangeType::RA)); + // The following two attempts are expected to throw because + // invalid exchange types are passed (XCHG_RA instead of XCHG_DO) + EXPECT_THROW( + stats_mgr->passSentPacket(ExchangeType::RA, sent_packet), + BadValue + ); + EXPECT_THROW( + stats_mgr->passRcvdPacket(ExchangeType::RA, rcvd_packet), + BadValue + ); + + // The following two attempts are expected to run fine because + // right exchange type is specified. + EXPECT_NO_THROW( + stats_mgr->passSentPacket(ExchangeType::DO, sent_packet) + ); + EXPECT_NO_THROW( + stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet) + ); +} + +TEST_F(StatsMgrTest, MultipleExchanges) { + CommandOptions opt; + boost::shared_ptr<StatsMgr> stats_mgr(new StatsMgr(opt)); + stats_mgr->addExchangeStats(ExchangeType::SA); + stats_mgr->addExchangeStats(ExchangeType::RR); + + // Simulate sending number of solicit packets. + const int solicit_packets_num = 10; + passMultiplePackets6(stats_mgr, ExchangeType::SA, DHCPV6_SOLICIT, + solicit_packets_num); + + // Simulate sending number of request packets. It is important that + // number of request packets is different then number of solicit + // packets. We can now check if right number packets went to + // the right exchange type group. + const int request_packets_num = 5; + passMultiplePackets6(stats_mgr, ExchangeType::RR, DHCPV6_REQUEST, + request_packets_num); + + // Check if all packets are successfully passed to packet lists. + EXPECT_EQ(solicit_packets_num, + stats_mgr->getSentPacketsNum(ExchangeType::SA)); + EXPECT_EQ(request_packets_num, + stats_mgr->getSentPacketsNum(ExchangeType::RR)); + + // Simulate reception of multiple packets for both SOLICIT-ADVERTISE + // and REQUEST-REPLY exchanges. Assume no packet drops. + const bool receive_packets = true; + passMultiplePackets6(stats_mgr, ExchangeType::SA, DHCPV6_ADVERTISE, + solicit_packets_num, receive_packets); + + passMultiplePackets6(stats_mgr, ExchangeType::RR, DHCPV6_REPLY, + request_packets_num, receive_packets); + + // Verify that all received packets are counted. + EXPECT_EQ(solicit_packets_num, + stats_mgr->getRcvdPacketsNum(ExchangeType::SA)); + EXPECT_EQ(request_packets_num, + stats_mgr->getRcvdPacketsNum(ExchangeType::RR)); +} + +TEST_F(StatsMgrTest, SendReceiveSimple) { + CommandOptions opt; + boost::scoped_ptr<StatsMgr> stats_mgr(new StatsMgr(opt)); + boost::shared_ptr<Pkt4> sent_packet(createPacket4(DHCPDISCOVER, + common_transid)); + boost::shared_ptr<Pkt4> rcvd_packet(createPacket4(DHCPOFFER, + common_transid)); + stats_mgr->addExchangeStats(ExchangeType::DO); + // The following attempt is expected to pass because the right + // exchange type is used. + ASSERT_NO_THROW( + stats_mgr->passSentPacket(ExchangeType::DO, sent_packet) + ); + // It is ok, to pass to received packets here. First one will + // be matched with sent packet. The latter one will not be + // matched with sent packet but orphans counter will simply + // increase. + ASSERT_NO_THROW( + stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet) + ); + ASSERT_NO_THROW( + stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet) + ); + EXPECT_EQ(1, stats_mgr->getOrphans(ExchangeType::DO)); +} + +TEST_F(StatsMgrTest, SendReceiveUnordered) { + CommandOptions opt; + const int packets_num = 10; + boost::scoped_ptr<StatsMgr> stats_mgr(new StatsMgr(opt)); + stats_mgr->addExchangeStats(ExchangeType::DO); + + // Transaction ids of 10 packets to be sent and received. + uint32_t transid[packets_num] = + { 1, 1024, 2, 1025, 3, 1026, 4, 1027, 5, 1028 }; + for (int i = 0; i < packets_num; ++i) { + boost::shared_ptr<Pkt4> sent_packet(createPacket4(DHCPDISCOVER, + transid[i])); + ASSERT_NO_THROW( + stats_mgr->passSentPacket(ExchangeType::DO, sent_packet) + ); + } + + // We are simulating that received packets are coming in reverse order: + // 1028, 5, 1027 .... + for (int i = 0; i < packets_num; ++i) { + boost::shared_ptr<Pkt4> + rcvd_packet(createPacket4(DHCPDISCOVER, + transid[packets_num - 1 - i])); + ASSERT_NO_THROW( + stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet); + ); + } + // All packets are expected to match (we did not drop any) + EXPECT_EQ(0, stats_mgr->getOrphans(ExchangeType::DO)); + // Most of the time we have to do unordered lookups except for the last + // one. Packets are removed from the sent list every time we have a match + // so eventually we come up with the single packet that caching iterator + // is pointing to. This is counted as ordered lookup. + EXPECT_EQ(1, stats_mgr->getOrderedLookups(ExchangeType::DO)); + EXPECT_EQ(9, stats_mgr->getUnorderedLookups(ExchangeType::DO)); +} + +TEST_F(StatsMgrTest, SendReceiveCollected) { + // Check that the packet collection mechanism works fine + // for any packet returned by the server. + for (unsigned int i = 0; i < TEST_COLLECTED_PKT_NUM; ++i) { + testSendReceiveCollected(i); + } +} + +TEST_F(StatsMgrTest, Orphans) { + CommandOptions opt; + const int packets_num = 6; + boost::scoped_ptr<StatsMgr> stats_mgr(new StatsMgr(opt)); + stats_mgr->addExchangeStats(ExchangeType::DO); + + // We skip every second packet to simulate drops. + for (int i = 0; i < packets_num; i += 2) { + boost::shared_ptr<Pkt4> sent_packet(createPacket4(DHCPDISCOVER, i)); + ASSERT_NO_THROW( + stats_mgr->passSentPacket(ExchangeType::DO, sent_packet) + ); + } + // We pass all received packets. + for (int i = 0; i < packets_num; ++i) { + boost::shared_ptr<Pkt4> rcvd_packet(createPacket4(DHCPOFFER, i)); + ASSERT_NO_THROW( + stats_mgr->passRcvdPacket(ExchangeType::DO, rcvd_packet); + ); + } + // The half of received packets are expected not to have matching + // sent packet. + EXPECT_EQ(packets_num / 2, stats_mgr->getOrphans(ExchangeType::DO)); +} + +TEST_F(StatsMgrTest, Delays) { + CommandOptions opt; + boost::shared_ptr<StatsMgr> stats_mgr(new StatsMgr(opt)); + stats_mgr->addExchangeStats(ExchangeType::DO, 5); + + // Send DISCOVER, wait 2s and receive OFFER. This will affect + // counters in Stats Manager. + passDOPacketsWithDelay(stats_mgr, 2, common_transid); + + // Initially min delay is equal to MAX_DOUBLE. After first packets + // are passed, it is expected to set to actual value. + EXPECT_LT(stats_mgr->getMinDelay(ExchangeType::DO), + std::numeric_limits<double>::max()); + EXPECT_GT(stats_mgr->getMinDelay(ExchangeType::DO), 1); + + // Max delay is supposed to the same value as minimum + // or maximum delay. + EXPECT_GT(stats_mgr->getMaxDelay(ExchangeType::DO), 1); + + // Delay sums are now the same as minimum or maximum delay. + EXPECT_GT(stats_mgr->getAvgDelay(ExchangeType::DO), 1); + + // Simulate another DISCOVER-OFFER exchange with delay between + // sent and received packets. Delay is now shorter than earlier + // so standard deviation of delay will now increase. + const unsigned int delay2 = 1; + passDOPacketsWithDelay(stats_mgr, delay2, common_transid + 1); + // Standard deviation is expected to be non-zero. + EXPECT_GT(stats_mgr->getStdDevDelay(ExchangeType::DO), 0); +} + +TEST_F(StatsMgrTest, CustomCounters) { + CommandOptions opt; + boost::scoped_ptr<StatsMgr> stats_mgr(new StatsMgr(opt)); + + // Specify counter keys and names. + const std::string too_short_key("tooshort"); + const std::string too_short_name("Too short packets"); + const std::string too_late_key("toolate"); + const std::string too_late_name("Packets sent too late"); + + // Add two custom counters. + stats_mgr->addCustomCounter(too_short_key, too_short_name); + stats_mgr->addCustomCounter(too_late_key, too_late_name); + + // Increment one of the counters 10 times. + const uint64_t tooshort_num = 10; + for (uint64_t i = 0; i < tooshort_num; ++i) { + stats_mgr->incrementCounter(too_short_key); + } + + // Increment another counter by 5 times. + const uint64_t toolate_num = 5; + for (uint64_t i = 0; i < toolate_num; ++i) { + stats_mgr->incrementCounter(too_late_key); + } + + // Check counter's current value and name. + CustomCounterPtr tooshort_counter = + stats_mgr->getCounter(too_short_key); + EXPECT_EQ(too_short_name, tooshort_counter->getName()); + EXPECT_EQ(tooshort_num, tooshort_counter->getValue()); + + // Check counter's current value and name. + CustomCounterPtr toolate_counter = + stats_mgr->getCounter(too_late_key); + EXPECT_EQ(too_late_name, toolate_counter->getName()); + EXPECT_EQ(toolate_num, toolate_counter->getValue()); + +} + +TEST_F(StatsMgrTest, PrintStats) { + std::cout << "This unit test is checking statistics printing " + << "capabilities. It is expected that some counters " + << "will be printed during this test. It may also " + << "cause spurious errors." << std::endl; + CommandOptions opt; + boost::shared_ptr<StatsMgr> stats_mgr(new StatsMgr(opt)); + stats_mgr->addExchangeStats(ExchangeType::SA); + + // Simulate sending and receiving one packet. Otherwise printing + // functions will complain about lack of packets. + const int packets_num = 1; + passMultiplePackets6(stats_mgr, ExchangeType::SA, DHCPV6_SOLICIT, + packets_num); + passMultiplePackets6(stats_mgr, ExchangeType::SA, DHCPV6_ADVERTISE, + packets_num, true); + + // This function will print statistics even if packets are not + // archived because it relies on counters. There is at least one + // exchange needed to count the average delay and std deviation. + EXPECT_NO_THROW(stats_mgr->printStats()); + + // Printing timestamps is expected to fail because by default we + // disable packets archiving mode. Without packets we can't get + // timestamps. + EXPECT_THROW(stats_mgr->printTimestamps(), isc::InvalidOperation); + + // Now, we create another statistics manager instance and enable timestamp + // printing, thus also enabling packets archiving mode. + CommandOptionsHelper::process(opt, "perfdhcp -x t 127.0.0.1"); + stats_mgr.reset(new StatsMgr(opt)); + stats_mgr->addExchangeStats(ExchangeType::SA); + + // Timestamps should now get printed because packets have been preserved. + EXPECT_NO_THROW(stats_mgr->printTimestamps()); + + // Create another statistics manager instance and enable lease printing for + // v4, thus also enabling packets archiving mode. + CommandOptionsHelper::process(opt, "perfdhcp -4 -x l 127.0.0.1"); + stats_mgr.reset(new StatsMgr(opt)); + stats_mgr->addExchangeStats(ExchangeType::RNA); + stats_mgr->addExchangeStats(ExchangeType::RLA); + ASSERT_TRUE(stats_mgr->hasExchangeStats(ExchangeType::DO)); + ASSERT_TRUE(stats_mgr->hasExchangeStats(ExchangeType::RA)); + ASSERT_TRUE(stats_mgr->hasExchangeStats(ExchangeType::RNA)); + ASSERT_TRUE(stats_mgr->hasExchangeStats(ExchangeType::RLA)); + + // Leases should now get printed because packets have been preserved. + EXPECT_NO_THROW(stats_mgr->printLeases()); + + // For v6 this time. + CommandOptionsHelper::process(opt, "perfdhcp -6 -x l 127.0.0.1"); + stats_mgr.reset(new StatsMgr(opt)); + stats_mgr->addExchangeStats(ExchangeType::RN); + stats_mgr->addExchangeStats(ExchangeType::RL); + ASSERT_TRUE(stats_mgr->hasExchangeStats(ExchangeType::SA)); + ASSERT_TRUE(stats_mgr->hasExchangeStats(ExchangeType::RR)); + ASSERT_TRUE(stats_mgr->hasExchangeStats(ExchangeType::RN)); + ASSERT_TRUE(stats_mgr->hasExchangeStats(ExchangeType::RL)); + + // Leases should now get printed because packets have been preserved. + EXPECT_NO_THROW(stats_mgr->printLeases()); +} + +} // namespace diff --git a/src/bin/perfdhcp/tests/test_control_unittest.cc b/src/bin/perfdhcp/tests/test_control_unittest.cc new file mode 100644 index 0000000..1838a7b --- /dev/null +++ b/src/bin/perfdhcp/tests/test_control_unittest.cc @@ -0,0 +1,1971 @@ +// Copyright (C) 2012-2023 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include "command_options_helper.h" +#include "../test_control.h" + +#include <asiolink/io_address.h> +#include <exceptions/exceptions.h> +#include <dhcp/dhcp4.h> +#include <dhcp/pkt4.h> +#include <dhcp/iface_mgr.h> +#include <dhcp/option_int.h> +#include <dhcp/option6_iaaddr.h> +#include <dhcp/option6_iaprefix.h> + +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/foreach.hpp> +#include <boost/format.hpp> + +#include <algorithm> +#include <cstddef> +#include <stdint.h> +#include <string> +#include <vector> +#include <fstream> +#include <gtest/gtest.h> + +using namespace std; +using namespace boost::posix_time; +using namespace isc; +using namespace isc::dhcp; +using namespace isc::perfdhcp; + +/// \brief FakePerfSocket class that mocks PerfSocket. +/// +/// It stubs send and receive operations and collects statistics. +class FakeTestControlPerfSocket: public BasePerfSocket { +public: + /// \brief Default constructor for FakePerfSocket. + FakeTestControlPerfSocket() : + iface_(boost::make_shared<Iface>("fake", 0)), + sent_cnt_(0), + recv_cnt_(0) {}; + + IfacePtr iface_; ///< Local fake interface. + + int sent_cnt_; ///< Counter of sent packets + int recv_cnt_; ///< Counter of received packets. + + /// \brief Simulate receiving DHCPv4 packet. + virtual dhcp::Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec) override { + (void)timeout_sec; // silence compile 'unused parameter' warning; + (void)timeout_usec; // silence compile 'unused parameter' warning; + recv_cnt_++; + return(dhcp::Pkt4Ptr()); + }; + + /// \brief Simulate receiving DHCPv6 packet. + virtual dhcp::Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec) override { + (void)timeout_sec; // silence compile 'unused parameter' warning; + (void)timeout_usec; // silence compile 'unused parameter' warning; + recv_cnt_++; + return(dhcp::Pkt6Ptr()); + }; + + /// \brief Simulate sending DHCPv4 packet. + virtual bool send(const dhcp::Pkt4Ptr& pkt) override { + sent_cnt_++; + pkt->updateTimestamp(); + sent_pkts4_.push_back(pkt); + return true; + }; + + /// \brief Simulate sending DHCPv6 packet. + virtual bool send(const dhcp::Pkt6Ptr& pkt) override { + sent_cnt_++; + pkt->updateTimestamp(); + sent_pkts6_.push_back(pkt); + return true; + }; + + /// \brief Override getting interface. + virtual IfacePtr getIface() override { return iface_; } + + void reset() { + sent_cnt_ = 0; + recv_cnt_ = 0; + } + + std::vector<dhcp::Pkt4Ptr> sent_pkts4_; /// output v4 packets are stored here + std::vector<dhcp::Pkt6Ptr> sent_pkts6_; /// output v6 packets are stored here +}; + + +/// \brief Test Control class with protected members made public. +/// +/// This class makes protected TestControl class's members public +/// to allow unit testing. +class NakedTestControl: public TestControl { +public: + + /// \brief Incremental transaction id generator. + /// + /// This is incremental transaction id generator. It overrides + /// the default transaction id generator that generates transaction + /// ids using random function. This generator will generate values + /// like: 1,2,3 etc. + class IncrementalGenerator : public TestControl::NumberGenerator { + public: + /// \brief Default constructor. + IncrementalGenerator() : + NumberGenerator(), + transid_(0) { + } + + /// \brief Generate unique transaction id. + /// + /// Generate unique transaction ids incrementally: + /// 1,2,3,4 etc. + /// + /// \return generated transaction id. + virtual uint32_t generate() { + return (++transid_); + } + + /// \brief Return next transaction id value. + uint32_t getNext() const { + return (transid_ + 1); + } + + private: + uint32_t transid_; ///< Last generated transaction id. + }; + + /// \brief Pointer to incremental generator. + typedef boost::shared_ptr<IncrementalGenerator> IncrementalGeneratorPtr; + + using TestControl::createMessageFromReply; + using TestControl::createMessageFromAck; + using TestControl::factoryElapsedTime6; + using TestControl::factoryGeneric; + using TestControl::factoryIana6; + using TestControl::factoryOptionRequestOption6; + using TestControl::factoryRapidCommit6; + using TestControl::factoryRequestList4; + using TestControl::generateClientId; + using TestControl::generateDuid; + using TestControl::generateMacAddress; + using TestControl::getTemplateBuffer; + using TestControl::initPacketTemplates; + using TestControl::processReceivedPacket4; + using TestControl::processReceivedPacket6; + using TestControl::registerOptionFactories; + using TestControl::reset; + using TestControl::sendDiscover4; + using TestControl::sendRequest4; + using TestControl::sendPackets; + using TestControl::sendMultipleMessages4; + using TestControl::sendMultipleMessages6; + using TestControl::sendRequest6; + using TestControl::sendSolicit6; + using TestControl::setDefaults4; + using TestControl::setDefaults6; + using TestControl::socket_; + using TestControl::last_report_; + using TestControl::transid_gen_; + using TestControl::macaddr_gen_; + using TestControl::first_packet_serverid_; + using TestControl::interrupted_; + using TestControl::template_packets_v4_; + using TestControl::template_packets_v6_; + using TestControl::ack_storage_; + using TestControl::sendMessageFromAck; + using TestControl::options_; + using TestControl::stats_mgr_; + + FakeTestControlPerfSocket fake_sock_; + + NakedTestControl(CommandOptions &opt) : TestControl(opt, fake_sock_) { + uint32_t clients_num = opt.getClientsNum() == 0 ? + 1 : opt.getClientsNum(); + setMacAddrGenerator(NumberGeneratorPtr(new TestControl::SequentialGenerator(clients_num))); + }; +}; + + +/// \brief Test Fixture Class +/// +/// This test fixture class is used to perform +/// unit tests on perfdhcp TestControl class. +class TestControlTest : public virtual ::testing::Test +{ +public: + + typedef std::vector<uint8_t> MacAddress; + typedef MacAddress::iterator MacAddressIterator; + + typedef std::vector<uint8_t> Duid; + typedef Duid::iterator DuidIterator; + + /// \brief Default Constructor + TestControlTest() { } + + /// \brief Create packet template file from binary data. + /// + /// Function creates file containing data from the provided buffer + /// in hexadecimal format. The size parameter specifies the maximum + /// size of the file. If total number of hexadecimal digits resulting + /// from buffer size is greater than maximum file size the file is + /// truncated. + /// + /// \param filename template file to be created. + /// \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. + bool createTemplateFile(const std::string& filename, + const std::vector<uint8_t>& buf, + const size_t size, + const bool invalid_chars = false) const { + std::ofstream temp_file; + temp_file.open(filename.c_str(), ios::out | ios::trunc); + if (!temp_file.is_open()) { + return (false); + } + for (size_t i = 0; i < buf.size(); ++i) { + int first_digit = buf[i] / 16; + int second_digit = buf[i] % 16; + // Insert two spaces between two hexadecimal digits. + // Spaces are allowed in template files. + temp_file << std::string(2, ' '); + if (2 * i + 1 < size) { + if (!invalid_chars) { + temp_file << std::hex << first_digit << second_digit << std::dec; + } else { + temp_file << "XY"; + } + } else if (2 * i < size) { + if (!invalid_chars) { + temp_file << std::hex << first_digit; + } else { + temp_file << "X"; + } + } else { + break; + } + } + temp_file.close(); + return (true); + } + + /// \brief Get full path to a file in testdata directory. + /// + /// \param filename filename being appended to absolute + /// path to testdata directory + /// + /// \return full path to a file in testdata directory. + std::string getFullPath(const std::string& filename) const { + std::ostringstream stream; + stream << TEST_DATA_DIR << "/" << filename; + return (stream.str()); + } + + /// \brief Match requested options in the buffer with given list. + /// + /// This method iterates through options provided in the buffer + /// and matches them with the options specified with first parameter. + /// Options in both vectors may be laid in different order. + /// + /// \param requested_options reference buffer with options. + /// \param buf test buffer with options that will be matched. + /// \return number of options from the buffer matched with options + /// in the reference buffer. + int matchRequestedOptions(const dhcp::OptionBuffer& requested_options, + const dhcp::OptionBuffer& buf) const { + size_t matched_num = 0; + for (size_t i = 0; i < buf.size(); ++i) { + for (size_t j = 0; j < requested_options.size(); ++j) { + if (requested_options[j] == buf[i]) { + // Requested option has been found. + ++matched_num; + } + } + } + return (matched_num); + } + + /// \brief Match requested DHCPv6 options in the buffer with given list. + /// + /// This method iterates through options provided in the buffer and + /// matches them with the options specified with first parameter. + /// Options in both vectors ma be laid in different order. + /// + /// \param requested_options reference buffer with options. + /// \param buf test buffer with options that will be matched. + /// \return number of options from the buffer matched with options in + /// the reference buffer or -1 if error occurred. + int matchRequestedOptions6(const dhcp::OptionBuffer& requested_options, + const dhcp::OptionBuffer& buf) const { + // Sanity check. + if ((requested_options.size() % 2 != 0) || + (buf.size() % 2 != 0)) { + return -1; + } + size_t matched_num = 0; + for (size_t i = 0; i < buf.size(); i += 2) { + for (size_t j = 0; j < requested_options.size(); j += 2) { + uint16_t opt_i = (buf[i + 1] << 8) + (buf[i] & 0xFF); + uint16_t opt_j = (requested_options[j + 1] << 8) + + (requested_options[j] & 0xFF); + if (opt_i == opt_j) { + // Requested option has been found. + ++matched_num; + } + } + } + return (matched_num); + } + + /// \brief Calculate the maximum vectors' mismatch position. + /// + /// This helper function calculates the maximum mismatch position + /// between two vectors (two different DUIDs or MAC addresses). + /// Calculated position is counted from the end of vectors. + /// Calculation is based on number of simulated clients. When number + /// of clients is less than 256 different DUIDs or MAC addresses can + /// can be coded in such a way that they differ on last vector element. + /// If number of clients is between 257 and 65536 they can differ + /// on two last positions so the returned value will be 2 and so on. + /// + /// \param clients_num number of simulated clients + /// \return maximum mismatch position + int unequalOctetPosition(int clients_num) const { + if (!clients_num) { + return (0); + } + clients_num--; + + int cnt = 0; + while (clients_num) { + clients_num >>= 8; + ++cnt; + } + + return (cnt); + } + + /// \brief Test generation of multiple DUIDs + /// + /// 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 + /// MAC address can be randomized depending on the number of + /// simulated clients. The DUID-LLT and HW type are expected to + /// be constant. The time value has to be properly calculated + /// as the number of seconds since DUID time epoch. The parts + /// of MAC address has to change if multiple clients are simulated + /// and do not change if single client is simulated. + void testDuid(CommandOptions &opt) const { + int clients_num = opt.getClientsNum(); + // Initialize Test Control class. + NakedTestControl tc(opt); + // The old duid will be holding the previously generated DUID. + // It will be used to compare against the new one. If we have + // multiple clients we want to make sure that duids differ. + uint8_t randomized = 0; + Duid old_duid(tc.generateDuid(randomized)); + Duid new_duid(0); + // total_dist shows the total difference between generated duid. + // It has to be greater than zero if multiple clients are simulated. + size_t total_dist = 0; + // Number of unique DUIDs. + size_t unique_duids = 0; + // Holds the position if the octet on which two DUIDS can be different. + // If number of clients is 256 or less it is last DUID octet (except for + // single client when subsequent DUIDs have to be equal). If number of + // clients is between 257 and 65536 the last two octets can differ etc. + int unequal_pos = unequalOctetPosition(clients_num); + // Keep generated DUIDs in this container. + std::list<std::vector<uint8_t> > duids; + // Perform number of iterations to generate number of DUIDs. + for (int i = 0; i < 10 * clients_num; ++i) { + if (new_duid.empty()) { + new_duid = old_duid; + } else { + std::swap(old_duid, new_duid); + new_duid = tc.generateDuid(randomized); + } + // The DUID-LLT is expected to start with DUID_LLT value + // of 1 and hardware ethernet type equal to 1 (HWETHER_TYPE). + const uint8_t duid_llt_and_hw[4] = { 0x0, 0x1, 0x0, 0x1 }; + // We assume DUID-LLT length 14. This includes 4 octets of + // DUID_LLT value, two octets of hardware type, 4 octets + // of time value and 6 octets of variable link layer (MAC) + // address. + const int duid_llt_size = 14; + ASSERT_EQ(duid_llt_size, new_duid.size()); + // The first four octets do not change. + EXPECT_TRUE(std::equal(new_duid.begin(), new_duid.begin() + 4, + duid_llt_and_hw)); + + // As described in RFC 8415: 'the time value is the time + // that the DUID is generated represented in seconds + // since midnight (UTC), January 1, 2000, modulo 2^32.' + uint32_t duid_time = 0; + // Pick 4 bytes of the time from generated DUID and put them + // in reverse order (in DUID they are stored in network order). + for (int j = 4; j < 8; ++j) { + duid_time |= new_duid[j] << (j - 4); + } + // Calculate the duration since epoch time. + ptime now = microsec_clock::universal_time(); + ptime duid_epoch(from_iso_string("20000101T000000")); + time_period period(duid_epoch, now); + + // Current time is the same or later than time from the DUID because + // DUID had been generated before reference duration was calculated. + EXPECT_GE(period.length().total_seconds(), duid_time); + + // Get the mismatch position (counting from the end) of + // mismatched octet between previously generated DUID + // and current. + std::pair<DuidIterator, DuidIterator> mismatch_pos = + std::mismatch(old_duid.begin(), old_duid.end(), + new_duid.begin()); + size_t mismatch_dist = + std::distance(mismatch_pos.first, old_duid.end()); + // For single client total_dist is expected to be 0 because + // old_duid and new_duid should always match. If we have + // more clients then duids have to differ except the case + // if randomization algorithm generates the same values but + // this would be an error in randomization algorithm. + total_dist += mismatch_dist; + // Mismatch may have occurred on the DUID octet position + // up to calculated earlier unequal_pos. + ASSERT_LE(mismatch_dist, unequal_pos); + // unique will inform if tested DUID is unique. + bool unique = true; + for (std::list<std::vector<uint8_t> >::const_iterator it = + duids.begin(); + it != duids.end(); ++it) { + // DUIDs should be of the same size if we want to compare them. + ASSERT_EQ(new_duid.size(), it->size()); + // Check if DUID is unique. + if (std::equal(new_duid.begin(), new_duid.end(), it->begin())) { + unique = false; + } + } + // Expecting that DUIDs will be unique only when + // first clients-num iterations is performed. + // After that, DUIDs become non unique. + if (unique) { + ++unique_duids; + } + // For number of iterations equal to clients_num,2*clients_num + // 3*clients_num ... we have to have number of unique duids + // equal to clients_num. + if ((i != 0) && (i % clients_num == 0)) { + ASSERT_EQ(clients_num, unique_duids); + } + // Remember generated DUID. + duids.push_back(new_duid); + } + // If we have more than one client at least one mismatch occurred. + if (clients_num < 2) { + EXPECT_EQ(0, total_dist); + } + } + + /// \brief Test DHCPv4 exchanges. + /// + /// Function simulates DHCPv4 exchanges. Function caller specifies + /// number of exchanges to be simulated and number of simulated + /// responses. When number of responses is lower than number of + /// iterations than the difference between them is the number + /// of simulated packet drops. This is useful to test if program + /// exit conditions are handled properly (maximum number of packet + /// drops specified as -D<max-drops> is taken into account). + /// + /// \param iterations_num number of exchanges to simulate. + /// \param receive_num number of received OFFER packets. + /// \param tc test control instance + void testPkt4Exchange(int iterations_num, + int receive_num, + bool use_templates, + NakedTestControl& tc) const { + //int sock_handle = 0; + + // Use templates files to crate packets. + if (use_templates) { + tc.initPacketTemplates(); + tc.getTemplateBuffer(0); + tc.getTemplateBuffer(1); + } + + // Incremental transaction id generator will generate + // predictable values of transaction id for each iteration. + // This is important because we need to simulate responses + // from the server and use the same transaction ids as in + // packets sent by client. + NakedTestControl::IncrementalGeneratorPtr + generator(new NakedTestControl::IncrementalGenerator()); + tc.setTransidGenerator(generator); + for (int i = 0; i < iterations_num; ++i) { + // Get next transaction id, without actually using it. The same + // id will be used by the TestControl class for DHCPDISCOVER. + uint32_t transid = generator->getNext(); + if (use_templates) { + tc.sendDiscover4(tc.getTemplateBuffer(0)); + } else { + tc.sendDiscover4(); + } + + // Do not simulate responses for packets later + // that specified as receive_num. This simulates + // packet drops. + if (i < receive_num) { + boost::shared_ptr<Pkt4> offer_pkt4(createOfferPkt4(transid)); + tc.processReceivedPacket4(offer_pkt4); + } + } + } + + /// \brief Test DHCPv6 exchanges. + /// + /// Function simulates DHCPv6 exchanges. Function caller specifies + /// number of exchanges to be simulated and number of simulated + /// responses. When number of responses is lower than number of + /// iterations than the difference between them is the number + /// of simulated packet drops. This is useful to test if program + /// exit conditions are handled properly (maximum number of packet + /// drops specified as -D<max-drops> is taken into account). + /// + /// \param iterations_num number of exchanges to simulate. + /// \param receive_num number of received OFFER packets. + /// \param tc test control instance + void testPkt6Exchange(int iterations_num, + int receive_num, + bool use_templates, + NakedTestControl& tc) const { + //int sock_handle = 0; + + // Use templates files to crate packets. + if (use_templates) { + tc.initPacketTemplates(); + tc.getTemplateBuffer(0); + tc.getTemplateBuffer(1); + } + + // Incremental transaction id generator will generate + // predictable values of transaction id for each iteration. + // 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 + generator(new NakedTestControl::IncrementalGenerator()); + tc.setTransidGenerator(generator); + uint32_t transid = 0; + for (int i = 0; i < iterations_num; ++i) { + // Do not simulate responses for packets later + // that specified as receive_num. This simulates + // packet drops. + if (use_templates) { + tc.sendSolicit6(tc.getTemplateBuffer(0)); + } else { + tc.sendSolicit6(); + } + ++transid; + if (i < receive_num) { + boost::shared_ptr<Pkt6> + advertise_pkt6(createAdvertisePkt6(tc, transid)); + // Receive ADVERTISE and send REQUEST. + tc.processReceivedPacket6(advertise_pkt6); + ++transid; + } + } + } + + /// \brief Test generation of multiple MAC addresses. + /// + /// This method validates generation of multiple MAC addresses. + /// The MAC address can be randomized depending on the number + /// of simulated clients. This test checks if different MAC + /// addresses are generated if number of simulated clients is + /// greater than 1. It also checks if the same MAC addresses is + /// generated if only 1 client is simulated. + void testMacAddress(CommandOptions &opt) const { + int clients_num = opt.getClientsNum(); + // The old_mac will be holding the value of previously generated + // MAC address. We will be comparing the newly generated one with it + // to see if it changes when multiple clients are simulated or if it + // does not change when single client is simulated. + MacAddress old_mac(opt.getMacTemplate()); + // Holds the position if the octet on which two MAC addresses can + // be different. If number of clients is 256 or less it is last MAC + // octet (except for single client when subsequent MAC addresses + // have to be equal). If number of clients is between 257 and 65536 + // the last two octets can differ etc. + int unequal_pos = unequalOctetPosition(clients_num); + // Number of unique MACs. + size_t unique_macs = 0; + // Initialize Test Controller. + NakedTestControl tc(opt); + size_t total_dist = 0; + // Keep generated MACs in this container. + std::list<std::vector<uint8_t> > macs; + // Do many iterations to generate and test MAC address values. + for (int i = 0; i < clients_num * 10; ++i) { + // Generate new MAC address. + uint8_t randomized = 0; + MacAddress new_mac(tc.generateMacAddress(randomized)); + // Get the mismatch position (counting from the end) of + // mismatched octet between previously generated MAC address + // and current. + std::pair<MacAddressIterator, MacAddressIterator> mismatch_pos = + std::mismatch(old_mac.begin(), old_mac.end(), new_mac.begin()); + size_t mismatch_dist = + std::distance(mismatch_pos.first, old_mac.end()); + // For single client total_dist is expected to be 0 because + // old_mac and new_mac should always match. If we have + // more clients then MAC addresses have to differ except + // the case if randomization algorithm generates the same + // values but this would be an error in randomization algorithm. + total_dist += mismatch_dist; + // Mismatch may have occurred on the MAC address's octet position + // up to calculated earlier unequal_pos. + ASSERT_LE(mismatch_dist, unequal_pos); + // unique will inform if tested DUID is unique. + bool unique = true; + for (std::list<std::vector<uint8_t> >::const_iterator it = + macs.begin(); + it != macs.end(); ++it) { + // MACs should be of the same size if we want to compare them. + ASSERT_EQ(new_mac.size(), it->size()); + // Check if MAC is unique. + if (std::equal(new_mac.begin(), new_mac.end(), it->begin())) { + unique = false; + } + } + // Expecting that MACs will be unique only when + // first clients-num iterations is performed. + // After that, MACs become non unique. + if (unique) { + ++unique_macs; + } + // For number of iterations equal to clients_num,2*clients_num + // 3*clients_num ... we have to have number of unique MACs + // equal to clients_num. + if ((i != 0) && (i % clients_num == 0)) { + ASSERT_EQ(clients_num, unique_macs); + } + // Remember generated MAC. + macs.push_back(new_mac); + + } + if (clients_num < 2) { + EXPECT_EQ(total_dist, 0); + } + } + + /// \brief Test sending DHCPv4 renews. + /// + /// This function simulates acquiring 10 leases from the server. Returned + /// DHCPACK messages are cached and used to send renew messages. + /// The maximal number of messages which can be sent is equal to the + /// number of leases acquired (10). This function also checks that an + /// attempt to send more renew messages than the number of leases acquired + /// will fail. + /// + /// \param msg_type A type of the message which is simulated to be sent + /// (DHCPREQUEST in renew state or DHCPRELEASE). + void testSendRenewRelease4(const uint16_t msg_type) { + // Build a command line. Depending on the message type, we will use + // -f<renew-rate> or -F<release-rate> parameter. + CommandOptions opt; + std::ostringstream s; + s << "perfdhcp -4 -l fake -r 10 "; + s << (msg_type == DHCPREQUEST ? "-f" : "-F"); + s << " 10 -R 10 -L 10067 -n 10 127.0.0.1"; + processCmdLine(opt, s.str()); + // Create a test controller class. + NakedTestControl tc(opt); + // Set the transaction id generator to sequential to control to + // guarantee that transaction ids are predictable. + boost::shared_ptr<NakedTestControl::IncrementalGenerator> + generator(new NakedTestControl::IncrementalGenerator()); + tc.setTransidGenerator(generator); + + // Send a number of DHCPDISCOVER messages. Each generated message will + // be assigned a different transaction id, starting from 1 to 10. + tc.sendPackets(10); + + // Simulate DHCPOFFER responses from the server. Each DHCPOFFER is + // assigned a transaction id from the range of 1 to 10, so as they + // match the transaction ids from the DHCPDISCOVER messages. + for (unsigned i = generator->getNext() - 10; + i < generator->getNext(); ++i) { + Pkt4Ptr offer(createOfferPkt4(i)); + // If DHCPOFFER is matched with the DHCPDISCOVER the call below + // will trigger a corresponding DHCPREQUEST. They will be assigned + // transaction ids from the range from 11 to 20 (the range of + // 1 to 10 has been used by DHCPDISCOVER-DHCPOFFER). + tc.processReceivedPacket4(offer); + } + + // Requests have been sent, so now let's simulate responses from the + // server. Generate corresponding DHCPACK messages with the transaction + // ids from the range from 11 to 20. + for (unsigned i = generator->getNext() - 10; + i < generator->getNext(); ++i) { + Pkt4Ptr ack(createAckPkt4(i)); + // Each DHCPACK packet corresponds to the new lease acquired. Since + // -f<renew-rate> option has been specified, received Reply + // messages are held so as renew messages can be sent for + // existing leases. + tc.processReceivedPacket4(ack); + } + + uint64_t msg_num; + // Try to send 5 messages. It should be successful because 10 + // DHCPREQUEST messages has been received. For each of them we + // should be able to send renewal. + msg_num = tc.sendMultipleMessages4(msg_type, 5); + // Make sure that we have sent 5 messages. + EXPECT_EQ(5, msg_num); + + // Try to do it again. We should still have 5 Reply packets for + // which renews haven't been sent yet. + msg_num = tc.sendMultipleMessages4(msg_type, 5); + EXPECT_EQ(5, msg_num); + + // We used all the DHCPACK packets (we sent renew or release for each of + // them already). Therefore, no further renew messages should be sent + // before we acquire new leases. + msg_num = tc.sendMultipleMessages4(msg_type, 5); + // Make sure that no message has been sent. + EXPECT_EQ(0, msg_num); + } + + /// \brief Test that the DHCPREQUEST message is created correctly and + /// comprises expected values. + /// + /// \param msg_type A type of the message to be tested: + /// DHCPREQUEST in renew state or DHCPRELEASE. + void testCreateRenewRelease4(const uint16_t msg_type) { + // This command line specifies that the Release/Renew messages should + // be sent with the same rate as the Solicit messages. + CommandOptions opt; + std::ostringstream s; + s << "perfdhcp -4 -l lo -r 10 "; + s << (msg_type == DHCPREQUEST ? "-F" : "-f") << " 10"; + s << " -R 10 -L 10067 -n 10 127.0.0.1"; + processCmdLine(opt, s.str()); + // Create a test controller class. + NakedTestControl tc(opt); + // Set the transaction id generator which will be used by the + // createRenew or createRelease function to generate transaction id. + boost::shared_ptr<NakedTestControl::IncrementalGenerator> + generator(new NakedTestControl::IncrementalGenerator()); + tc.setTransidGenerator(generator); + + Pkt4Ptr ack = createAckPkt4(1); + + // Create DHCPREQUEST from DHCPACK. + Pkt4Ptr msg; + msg = tc.createMessageFromAck(msg_type, ack); + + // Make sure that the DHCPACK has been successfully created and that + // it holds expected data. + ASSERT_TRUE(msg); + EXPECT_EQ("127.0.0.1", msg->getCiaddr().toText()); + + // HW address. + HWAddrPtr hwaddr_ack = ack->getHWAddr(); + ASSERT_TRUE(hwaddr_ack); + HWAddrPtr hwaddr_req = msg->getHWAddr(); + ASSERT_TRUE(hwaddr_req); + EXPECT_TRUE(hwaddr_ack->hwaddr_ == hwaddr_req->hwaddr_); + + // Creating message from null DHCPACK should fail. + EXPECT_THROW(tc.createMessageFromAck(msg_type, Pkt4Ptr()), isc::BadValue); + + // Creating message from DHCPACK holding zero yiaddr should fail. + asiolink::IOAddress yiaddr = ack->getYiaddr(); + ack->setYiaddr(asiolink::IOAddress::IPV4_ZERO_ADDRESS()); + EXPECT_THROW(tc.createMessageFromAck(msg_type, ack), isc::BadValue); + ack->setYiaddr(yiaddr); + } + + /// \brief Test that the DHCPv6 Release or Renew message is created + /// correctly and comprises expected options. + /// + /// \param msg_type A type of the message to be tested: DHCPV6_RELEASE + /// or DHCPV6_RENEW. + void testCreateRenewRelease6(const uint16_t msg_type) { + // This command line specifies that the Release/Renew messages should + // be sent with the same rate as the Solicit messages. + CommandOptions opt; + std::ostringstream s; + s << "perfdhcp -6 -l lo -r 10 "; + s << (msg_type == DHCPV6_RELEASE ? "-F" : "-f") << " 10 "; + s << "-R 10 -L 10547 -n 10 -e address-and-prefix ::1"; + processCmdLine(opt, s.str()); + // Create a test controller class. + NakedTestControl tc(opt); + // Set the transaction id generator which will be used by the + // createRenew or createRelease function to generate transaction id. + boost::shared_ptr<NakedTestControl::IncrementalGenerator> + generator(new NakedTestControl::IncrementalGenerator()); + tc.setTransidGenerator(generator); + + // Create a Reply packet. The createRelease or createReply function will + // need Reply packet to create a corresponding Release or Reply. + Pkt6Ptr reply = createReplyPkt6(tc, 1); + + Pkt6Ptr msg; + // Check that the message is created. + msg = tc.createMessageFromReply(msg_type, reply); + + ASSERT_TRUE(msg); + // Check that the message type and transaction id is correct. + EXPECT_EQ(msg_type, msg->getType()); + EXPECT_EQ(1, msg->getTransid()); + + // Check that the message has expected options. These are the same for + // Release and Renew. + + // Client Identifier. + OptionPtr opt_clientid = msg->getOption(D6O_CLIENTID); + ASSERT_TRUE(opt_clientid); + EXPECT_TRUE(reply->getOption(D6O_CLIENTID)->getData() == + opt_clientid->getData()); + + // Server identifier + OptionPtr opt_serverid = msg->getOption(D6O_SERVERID); + ASSERT_TRUE(opt_serverid); + EXPECT_TRUE(reply->getOption(D6O_SERVERID)->getData() == + opt_serverid->getData()); + + // IA_NA + OptionPtr opt_ia_na = msg->getOption(D6O_IA_NA); + ASSERT_TRUE(opt_ia_na); + EXPECT_TRUE(reply->getOption(D6O_IA_NA)->getData() == + opt_ia_na->getData()); + + // IA_PD + OptionPtr opt_ia_pd = msg->getOption(D6O_IA_PD); + ASSERT_TRUE(opt_ia_pd); + EXPECT_TRUE(reply->getOption(D6O_IA_PD)->getData() == + opt_ia_pd->getData()); + + // Make sure that exception is thrown if the Reply message is NULL. + EXPECT_THROW(tc.createMessageFromReply(msg_type, Pkt6Ptr()), + isc::BadValue); + + } + + /// \brief Test sending DHCPv6 Releases or Renews. + /// + /// This function simulates acquiring 10 leases from the server. Returned + /// Reply messages are cached and used to send Renew or Release messages. + /// The maximal number of Renew or Release messages which can be sent is + /// equal to the number of leases acquired (10). This function also checks + /// that an attempt to send more Renew or Release messages than the number + /// of leases acquired will fail. + /// + /// \param msg_type A type of the message which is simulated to be sent + /// (DHCPV6_RENEW or DHCPV6_RELEASE). + void testSendRenewRelease6(const uint16_t msg_type) { + // Build a command line. Depending on the message type, we will use + // -f<renew-rate> or -F<release-rate> parameter. + CommandOptions opt; + std::ostringstream s; + s << "perfdhcp -6 -l fake -r 10 "; + s << (msg_type == DHCPV6_RENEW ? "-f" : "-F"); + s << " 10 -R 10 -L 10547 -n 10 ::1"; + processCmdLine(opt, s.str()); + // Create a test controller class. + NakedTestControl tc(opt); + // Set the transaction id generator to sequential to control to + // guarantee that transaction ids are predictable. + boost::shared_ptr<NakedTestControl::IncrementalGenerator> + generator(new NakedTestControl::IncrementalGenerator()); + tc.setTransidGenerator(generator); + + // Send a number of Solicit messages. Each generated Solicit will be + // assigned a different transaction id, starting from 1 to 10. + tc.sendPackets(10); + + // Simulate Advertise responses from the server. Each advertise is + // assigned a transaction id from the range of 1 to 10, so as they + // match the transaction ids from the Solicit messages. + for (unsigned i = generator->getNext() - 10; + i < generator->getNext(); ++i) { + Pkt6Ptr advertise(createAdvertisePkt6(tc, i)); + // If Advertise is matched with the Solicit the call below will + // trigger a corresponding Request. They will be assigned + // transaction ids from the range from 11 to 20 (the range of + // 1 to 10 has been used by Solicit-Advertise). + tc.processReceivedPacket6(advertise); + } + + // Requests have been sent, so now let's simulate responses from the + // server. Generate corresponding Reply messages with the transaction + // ids from the range from 11 to 20. + for (unsigned i = generator->getNext() - 10; + i < generator->getNext(); ++i) { + Pkt6Ptr reply(createReplyPkt6(tc, i)); + // Each Reply packet corresponds to the new lease acquired. Since + // -f<renew-rate> option has been specified, received Reply + // messages are held so as Renew messages can be sent for + // existing leases. + tc.processReceivedPacket6(reply); + } + + uint64_t msg_num; + // Try to send 5 messages. It should be successful because 10 Reply + // messages has been received. For each of them we should be able to + // send Renew or Release. + msg_num = tc.sendMultipleMessages6(msg_type, 5); + // Make sure that we have sent 5 messages. + EXPECT_EQ(5, msg_num); + + // Try to do it again. We should still have 5 Reply packets for + // which Renews or Releases haven't been sent yet. + msg_num = tc.sendMultipleMessages6(msg_type, 5); + EXPECT_EQ(5, msg_num); + + // We used all the Reply packets (we sent Renew or Release for each of + // them already). Therefore, no further Renew or Release messages should + // be sent before we acquire new leases. + msg_num = tc.sendMultipleMessages6(msg_type, 5); + // Make sure that no message has been sent. + EXPECT_EQ(0, msg_num); + + } + + /// \brief Test counting rejected leases in Solicit-Advertise. + /// + /// This function simulates acquiring 4 leases from the server and + /// rejecting allocating of 6 leases + + void testCountRejectedLeasesSolAdv() { + // Build a command line. + CommandOptions opt; + std::ostringstream s; + s << "perfdhcp -6 -l fake -r 10 -R 10 -L 10547 -n 10 ::1"; + processCmdLine(opt, s.str()); + // Create a test controller class. + NakedTestControl tc(opt); + // Set the transaction id generator to sequential to control to + // guarantee that transaction ids are predictable. + boost::shared_ptr<NakedTestControl::IncrementalGenerator> + generator(new NakedTestControl::IncrementalGenerator()); + tc.setTransidGenerator(generator); + + // Send a number of Solicit messages. Each generated Solicit will be + // assigned a different transaction id, starting from 1 to 10. + tc.sendPackets(10); + + // Simulate Advertise responses from the server. Each advertise is + // assigned a transaction id from the range of 1 to 6 with incorrect IA + // included in the message + for (uint32_t i = generator->getNext() - 10; i < 7; ++i) { + Pkt6Ptr advertise(createAdvertisePkt6(tc, i, false)); + tc.processReceivedPacket6(advertise); + } + // counter of rejected leases has to be 6 + EXPECT_EQ(tc.stats_mgr_.getRejLeasesNum(ExchangeType::SA), 6); + // Simulate Advertise responses from the server. Each advertise is + // assigned a transaction id from the range of 7 to 10 with correct IA + // included in the message + for (uint32_t i = generator->getNext() - 7; i < 11; ++i) { + Pkt6Ptr advertise(createAdvertisePkt6(tc, i)); + tc.processReceivedPacket6(advertise); + } + // counter of rejected leases can't change at this point + EXPECT_EQ(tc.stats_mgr_.getRejLeasesNum(ExchangeType::SA), 6); + } + + /// \brief Parse command line string with CommandOptions. + /// + /// \param cmdline command line string to be parsed. + /// \throw isc::Unexpected if unexpected error occurred. + /// \throw isc::InvalidParameter if command line is invalid. + void processCmdLine(CommandOptions &opt, const std::string& cmdline) const { + CommandOptionsHelper::process(opt, cmdline); + } + + /// \brief Create DHCPOFFER or DHCPACK packet. + /// + /// \param pkt_type DHCPOFFER or DHCPACK. + /// \param transid Transaction id. + /// + /// \return Instance of the packet. + Pkt4Ptr + createResponsePkt4(const uint8_t pkt_type, + const uint32_t transid) const { + Pkt4Ptr pkt(new Pkt4(pkt_type, transid)); + OptionPtr opt_serverid = Option::factory(Option::V4, + DHO_DHCP_SERVER_IDENTIFIER, + OptionBuffer(4, 1)); + pkt->setYiaddr(asiolink::IOAddress("127.0.0.1")); + pkt->addOption(opt_serverid); + pkt->updateTimestamp(); + return (pkt); + } + + /// \brief Create DHCPv4 OFFER packet. + /// + /// \param transid transaction id. + /// \return instance of the packet. + Pkt4Ptr + createOfferPkt4(uint32_t transid) const { + return (createResponsePkt4(DHCPOFFER, transid)); + } + + /// \brief Create DHCPACK packet. + /// + /// \param transid transaction id. + /// \return instance of the packet. + Pkt4Ptr + createAckPkt4(const uint32_t transid) const { + return (createResponsePkt4(DHCPACK, transid)); + } + + /// \brief Create DHCPv6 ADVERTISE packet. + /// + /// \param transid transaction id. + /// \return instance of the packet. + Pkt6Ptr + createAdvertisePkt6(NakedTestControl &tc, const uint32_t transid, + const bool validIA = true) const { + boost::shared_ptr<Pkt6> advertise(new Pkt6(DHCPV6_ADVERTISE, transid)); + // Add IA_NA if requested by the client. + if (tc.options_.getLeaseType().includes(CommandOptions::LeaseType::ADDRESS)) { + OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA); + if (validIA) { + OptionPtr iaaddr(new Option6IAAddr(D6O_IAADDR, + isc::asiolink::IOAddress("fe80::abcd"), 300, 500)); + opt_ia_na->addOption(iaaddr); + } + advertise->addOption(opt_ia_na); + } + // Add IA_PD if requested by the client. + if (tc.options_.getLeaseType().includes(CommandOptions::LeaseType::PREFIX)) { + OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD); + if (validIA) { + OptionPtr iapref(new Option6IAPrefix(D6O_IAPREFIX, + isc::asiolink::IOAddress("fe80::"), 64, 300, 500)); + opt_ia_pd->addOption(iapref); + } + advertise->addOption(opt_ia_pd); + } + OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID)); + uint8_t randomized = 0; + std::vector<uint8_t> duid(tc.generateDuid(randomized)); + OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid)); + advertise->addOption(opt_serverid); + advertise->addOption(opt_clientid); + advertise->updateTimestamp(); + return (advertise); + } + + Pkt6Ptr + createReplyPkt6(NakedTestControl &tc, const uint32_t transid, + const bool validIA = true) const { + Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, transid)); + // Add IA_NA if requested by the client. + if (tc.options_.getLeaseType().includes(CommandOptions::LeaseType::ADDRESS)) { + OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA); + if (validIA) { + OptionPtr iaaddr(new Option6IAAddr(D6O_IAADDR, + isc::asiolink::IOAddress("fe80::abcd"), 300, 500)); + opt_ia_na->addOption(iaaddr); + } + reply->addOption(opt_ia_na); + } + // Add IA_PD if requested by the client. + if (tc.options_.getLeaseType().includes(CommandOptions::LeaseType::PREFIX)) { + OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD); + if (validIA) { + OptionPtr iapref(new Option6IAPrefix(D6O_IAPREFIX, + isc::asiolink::IOAddress("fe80::"), 64, 300, 500)); + opt_ia_pd->addOption(iapref); + } + reply->addOption(opt_ia_pd); + } + OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID)); + uint8_t randomized = 0; + std::vector<uint8_t> duid(tc.generateDuid(randomized)); + OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid)); + reply->addOption(opt_serverid); + reply->addOption(opt_clientid); + reply->updateTimestamp(); + return (reply); + + } + + /// @brief Check presence and content of v4 options 55. + /// + /// \param pkt packet to be checked + /// \param expected_option_requests only these option requests should be + /// found under option 55 in the packet, nothing more, nothing less + void checkOptions55(Pkt4Ptr const& pkt, + vector<uint8_t> const& expected_option_requests) { + // Sanity checks + ASSERT_TRUE(pkt); + OptionPtr const& opt(pkt->getOption(55)); + ASSERT_TRUE(opt); + EXPECT_TRUE(opt->getUniverse() == Option::V4); + + // Create the text of the expected option. + string const length(to_string(expected_option_requests.size())); + string const buffer( + TestControl::vector2Hex(expected_option_requests, ":")); + string const expected_option_text(boost::str( + boost::format("type=055, len=%03u: %s") % length % buffer)); + + // Compare. + EXPECT_EQ(opt->toText(), expected_option_text); + } + + /// @brief check if v4 options 200 and 201 are present. + /// + /// The options are expected to have specific format, as if parameters + /// -o 200,abcdef1234, -o 201,00 were passed to the command line. + void checkOptions20x(const Pkt4Ptr& pkt) { + ASSERT_TRUE(pkt); + OptionPtr opt = pkt->getOption(200); + ASSERT_TRUE(opt); + EXPECT_TRUE(opt->getUniverse() == Option::V4); + EXPECT_EQ(opt->toText(), "type=200, len=005: ab:cd:ef:12:34"); + + opt = pkt->getOption(201); + ASSERT_TRUE(opt); + EXPECT_EQ(opt->toText(), "type=201, len=001: 00"); + } + + /// @brief check if v6 options 200 and 201 are present. + /// + /// The options are expected to have specific format, as if parameters + /// -o 200,abcdef1234, -o 201,00 were passed to the command line. + void checkOptions20x(const Pkt6Ptr& pkt) { + ASSERT_TRUE(pkt); + OptionPtr opt = pkt->getOption(200); + ASSERT_TRUE(opt); + EXPECT_TRUE(opt->getUniverse() == Option::V6); + EXPECT_EQ(opt->toText(), "type=00200, len=00005: ab:cd:ef:12:34"); + + opt = pkt->getOption(201); + ASSERT_TRUE(opt); + EXPECT_EQ(opt->toText(), "type=00201, len=00001: 00"); + } + +}; + +// This test verifies that the class members are reset to expected values. +TEST_F(TestControlTest, reset) { + CommandOptions opt; + processCmdLine(opt, "perfdhcp -4 127.0.0.1"); + NakedTestControl tc(opt); + tc.reset(); + EXPECT_FALSE(tc.last_report_.is_not_a_date_time()); + EXPECT_FALSE(tc.transid_gen_); + EXPECT_FALSE(tc.macaddr_gen_); + EXPECT_TRUE(tc.first_packet_serverid_.empty()); + EXPECT_FALSE(tc.interrupted_); + +} + +// This test verifies that the client id is generated from the HW address. +TEST_F(TestControlTest, generateClientId) { + // Generate HW address. + std::vector<uint8_t> hwaddr; + for (unsigned int i = 0; i < 6; ++i) { + hwaddr.push_back(i); + } + HWAddrPtr hwaddr_ptr(new HWAddr(hwaddr, 5)); + + // Use generated HW address to generate client id. + CommandOptions opt; + processCmdLine(opt, "perfdhcp -4 127.0.0.1"); + NakedTestControl tc(opt); + OptionPtr opt_client_id; + opt_client_id = tc.generateClientId(hwaddr_ptr); + ASSERT_TRUE(opt_client_id); + + // Extract the client id data. + const OptionBuffer& client_id = opt_client_id->getData(); + ASSERT_EQ(7, client_id.size()); + + // Verify that the client identifier is generated correctly. + + // First byte is the HW type. + EXPECT_EQ(5, client_id[0]); + // The rest of the client identifier should be equal to the HW address. + std::vector<uint8_t> sub(client_id.begin() + 1, client_id.end()); + EXPECT_TRUE(hwaddr == sub); +} + +TEST_F(TestControlTest, GenerateDuid) { + // Simple command line that simulates one client only. Always the + // same DUID will be generated. + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l 127.0.0.1 all"); + testDuid(opt); + + // Simulate 50 clients. Different DUID will be generated. + processCmdLine(opt, "perfdhcp -l 127.0.0.1 -R 50 all"); + testDuid(opt); + + // Checks that the random mac address returned by generateDuid + // is in the list of mac addresses in the mac-list.txt data file + std::string mac_list_full_path = getFullPath("mac-list.txt"); + std::ostringstream cmd; + cmd << "perfdhcp -M " << mac_list_full_path << " 127.0.0.1"; + processCmdLine(opt, cmd.str()); + // Initialize Test Controller. + NakedTestControl tc(opt); + uint8_t randomized = 0; + std::vector<uint8_t> generated_duid = tc.generateDuid(randomized); + + // Check that generated_duid is DUID_LL + ASSERT_EQ(10, generated_duid.size()); + DuidPtr duid(new DUID(generated_duid)); + ASSERT_EQ(duid->getType(), DUID::DUID_LL); + + // Make sure it's on the list + const CommandOptions::MacAddrsVector& macs = opt.getMacsFromFile(); + // DUID LL comprises 2 bytes of duid type, 2 bytes of hardware type, + // then 6 bytes of HW address. + vector<uint8_t> mac(6); + std::copy(generated_duid.begin() + 4, generated_duid.begin() + 10, + mac.begin()); + // Check that mac is in macs. + ASSERT_TRUE(std::find(macs.begin(), macs.end(), mac) != macs.end()); +} + +TEST_F(TestControlTest, GenerateMacAddress) { + CommandOptions opt; + // Simulate one client only. Always the same MAC address will be + // generated. + processCmdLine(opt, "perfdhcp -l 127.0.0.1 all"); + testMacAddress(opt); + + // Simulate 50 clients. Different MAC addresses will be generated. + processCmdLine(opt, "perfdhcp -l 127.0.0.1 -R 50 all"); + testMacAddress(opt); + + // Checks that the random mac address returned by generateMacAddress + // is in the list of mac addresses in the mac-list.txt data file + std::string mac_list_full_path = getFullPath("mac-list.txt"); + std::ostringstream cmd; + cmd << "perfdhcp -M " << mac_list_full_path << " 127.0.0.1"; + processCmdLine(opt, cmd.str()); + // Initialize Test Controller. + NakedTestControl tc(opt); + uint8_t randomized = 0; + // Generate MAC address and sanity check its size. + std::vector<uint8_t> mac = tc.generateMacAddress(randomized); + ASSERT_EQ(6, mac.size()); + // Make sure that the generated MAC address belongs to the MAC addresses + // read from a file. + const CommandOptions::MacAddrsVector& macs = opt.getMacsFromFile(); + ASSERT_TRUE(std::find(macs.begin(), macs.end(), mac) != macs.end()); +} + +TEST_F(TestControlTest, Options4) { + using namespace isc::dhcp; + CommandOptions opt; + processCmdLine(opt, "perfdhcp -4 127.0.0.1"); + NakedTestControl tc(opt); + // By default the IP version mode is V4 so there is no need to + // parse command line to override the IP version. Note that + // registerOptionFactories is used for both V4 and V6. + tc.registerOptionFactories(); + // Create option with buffer size equal to 1 and holding DHCPDISCOVER + // message type. + OptionPtr opt_msg_type(Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE, + OptionBuffer(1, DHCPDISCOVER))); + // Validate the option type and universe. + EXPECT_EQ(Option::V4, opt_msg_type->getUniverse()); + EXPECT_EQ(DHO_DHCP_MESSAGE_TYPE, opt_msg_type->getType()); + // Validate the message type from the option we have now created. + uint8_t msg_type = 0; + msg_type = opt_msg_type->getUint8(); + EXPECT_EQ(DHCPDISCOVER, msg_type); + + // Create another option: DHCP_PARAMETER_REQUEST_LIST + OptionPtr + opt_requested_options(Option::factory(Option::V4, + DHO_DHCP_PARAMETER_REQUEST_LIST)); + // Here is a list of options that we are requesting in the + // server's response. + const uint8_t requested_options[] = { + DHO_SUBNET_MASK, + DHO_BROADCAST_ADDRESS, + DHO_TIME_OFFSET, + DHO_ROUTERS, + DHO_DOMAIN_NAME, + DHO_DOMAIN_NAME_SERVERS, + DHO_HOST_NAME + }; + + OptionBuffer + requested_options_ref(requested_options, + requested_options + sizeof(requested_options)); + + // 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 separately. + const OptionBuffer& requested_options_buf = + opt_requested_options->getData(); + EXPECT_EQ(requested_options_ref.size(), requested_options_buf.size()); + size_t matched_num = matchRequestedOptions(requested_options_ref, + requested_options_buf); + // We want exactly the same requested options as listed in + // requested_options array - nothing more or less. + EXPECT_EQ(requested_options_ref.size(), matched_num); +} + +TEST_F(TestControlTest, Options6) { + using namespace isc::dhcp; + CommandOptions opt; + + // Lets override the IP version to test V6 options (-6 parameter) + processCmdLine(opt, "perfdhcp -l lo -6 ::1"); + + NakedTestControl tc(opt); + tc.registerOptionFactories(); + + // Validate the D6O_ELAPSED_TIME option. + OptionPtr opt_elapsed_time(Option::factory(Option::V6, D6O_ELAPSED_TIME)); + // Validate the option type and universe. + EXPECT_EQ(Option::V6, opt_elapsed_time->getUniverse()); + EXPECT_EQ(D6O_ELAPSED_TIME, opt_elapsed_time->getType()); + // The default value of elapsed time is zero. + uint16_t elapsed_time; + elapsed_time = opt_elapsed_time->getUint16(); + EXPECT_EQ(0, elapsed_time); + + // With the factory function we may also specify the actual + // value of elapsed time. Let's make use of std::vector + // constructor to create the option buffer, 2 octets long + // with each octet initialized to 0x1. + size_t elapsed_time_buf_size = 2; + uint8_t elapsed_time_pattern = 0x1; + OptionPtr + opt_elapsed_time2(Option::factory(Option::V6, D6O_ELAPSED_TIME, + OptionBuffer(elapsed_time_buf_size, + elapsed_time_pattern))); + + // Any buffer that has size neither equal to 0 nor 2 is considered invalid. + elapsed_time_buf_size = 1; + EXPECT_THROW( + Option::factory(Option::V6, D6O_ELAPSED_TIME, + OptionBuffer(elapsed_time_buf_size, elapsed_time_pattern)), + isc::BadValue + ); + + // Validate the option type and universe. + EXPECT_EQ(Option::V6, opt_elapsed_time2->getUniverse()); + EXPECT_EQ(D6O_ELAPSED_TIME, opt_elapsed_time2->getType()); + // Make sure the getUint16 does not throw exception. It wile throw + // buffer is shorter than 2 octets. + elapsed_time = opt_elapsed_time2->getUint16(); + // Check the expected value of elapsed time. + EXPECT_EQ(0x0101, elapsed_time); + + // Validate the D6O_RAPID_COMMIT option. + OptionPtr opt_rapid_commit(Option::factory(Option::V6, D6O_RAPID_COMMIT)); + // Validate the option type and universe. + EXPECT_EQ(Option::V6, opt_rapid_commit->getUniverse()); + EXPECT_EQ(D6O_RAPID_COMMIT, opt_rapid_commit->getType()); + // Rapid commit has no data payload. + EXPECT_THROW(opt_rapid_commit->getUint8(), isc::OutOfRange); + + // Validate the D6O_CLIENTID option. + OptionBuffer duid(opt.getDuidTemplate()); + OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid)); + EXPECT_EQ(Option::V6, opt_clientid->getUniverse()); + EXPECT_EQ(D6O_CLIENTID, opt_clientid->getType()); + const OptionBuffer& duid2 = opt_clientid->getData(); + ASSERT_EQ(duid.size(), duid2.size()); + // The Duid we set for option is the same we get. + EXPECT_TRUE(std::equal(duid.begin(), duid.end(), duid2.begin())); + + // Validate the D6O_ORO (Option Request Option). + OptionPtr opt_oro(Option::factory(Option::V6, D6O_ORO)); + // Prepare the reference buffer with requested options. + const uint8_t requested_options[] = { + 0, D6O_NAME_SERVERS, + 0, D6O_DOMAIN_SEARCH + }; + // Each option code in ORO is 2 bytes long. We calculate the number of + // requested options by dividing the size of the buffer holding options + // by the size of each individual option. + int requested_options_num = sizeof(requested_options) / sizeof(uint16_t); + OptionBuffer + requested_options_ref(requested_options, + requested_options + sizeof(requested_options)); + // Get the buffer from option. + const OptionBuffer& requested_options_buf = opt_oro->getData(); + // Size of reference buffer and option buffer have to be + // the same for comparison. + EXPECT_EQ(requested_options_ref.size(), requested_options_buf.size()); + // Check if all options in the buffer are matched with reference buffer. + size_t matched_num = matchRequestedOptions6(requested_options_ref, + requested_options_buf); + EXPECT_EQ(requested_options_num, matched_num); + + // Validate the D6O_IA_NA option. + OptionPtr opt_ia_na(Option::factory(Option::V6, D6O_IA_NA)); + EXPECT_EQ(Option::V6, opt_ia_na->getUniverse()); + EXPECT_EQ(D6O_IA_NA, opt_ia_na->getType()); + // Every IA_NA option is expected to start with this sequence. + const uint8_t opt_ia_na_array[] = { + 0, 0, 0, 1, // IAID = 1 + 0, 0, 3600 >> 8, 3600 & 0xff, // T1 = 3600 + 0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400 + }; + OptionBuffer opt_ia_na_ref(opt_ia_na_array, + opt_ia_na_array + sizeof(opt_ia_na_array)); + const OptionBuffer& opt_ia_na_buf = opt_ia_na->getData(); + ASSERT_EQ(opt_ia_na_buf.size(), opt_ia_na_ref.size()); + EXPECT_TRUE(std::equal(opt_ia_na_ref.begin(), opt_ia_na_ref.end(), + opt_ia_na_buf.begin())); + + // @todo Add more tests for IA address options. +} + +TEST_F(TestControlTest, Packet4) { + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -L 10547 all"); + NakedTestControl tc(opt); + uint32_t transid = 123; + boost::shared_ptr<Pkt4> pkt4(new Pkt4(DHCPDISCOVER, transid)); + // Set parameters on outgoing packet. + tc.setDefaults4(pkt4); + // Validate that packet has been setup correctly. + EXPECT_EQ(tc.fake_sock_.iface_->getName(), pkt4->getIface()); + EXPECT_EQ(tc.fake_sock_.ifindex_, pkt4->getIndex()); + EXPECT_EQ(DHCP4_CLIENT_PORT, pkt4->getLocalPort()); + EXPECT_EQ(DHCP4_SERVER_PORT, pkt4->getRemotePort()); + EXPECT_EQ(1, pkt4->getHops()); + EXPECT_EQ(asiolink::IOAddress("255.255.255.255"), + pkt4->getRemoteAddr()); + EXPECT_EQ(asiolink::IOAddress(tc.socket_.addr_), pkt4->getLocalAddr()); + EXPECT_EQ(asiolink::IOAddress(tc.socket_.addr_), pkt4->getGiaddr()); +} + +TEST_F(TestControlTest, Packet6) { + CommandOptions opt; + processCmdLine(opt, "perfdhcp -6 -l fake -L 10547 servers"); + NakedTestControl tc(opt); + uint32_t transid = 123; + boost::shared_ptr<Pkt6> pkt6(new Pkt6(DHCPV6_SOLICIT, transid)); + // Set packet's parameters. + tc.setDefaults6(pkt6); + // Validate if parameters have been set correctly. + EXPECT_EQ(tc.fake_sock_.iface_->getName(), pkt6->getIface()); + EXPECT_EQ(tc.socket_.ifindex_, pkt6->getIndex()); + EXPECT_EQ(DHCP6_CLIENT_PORT, pkt6->getLocalPort()); + EXPECT_EQ(DHCP6_SERVER_PORT, pkt6->getRemotePort()); + EXPECT_EQ(tc.socket_.addr_, pkt6->getLocalAddr()); + EXPECT_EQ(asiolink::IOAddress("FF05::1:3"), pkt6->getRemoteAddr()); + // Packet must not be relayed. + EXPECT_TRUE(pkt6->relay_info_.empty()); +} + +TEST_F(TestControlTest, Packet6Relayed) { + CommandOptions opt; + processCmdLine(opt, "perfdhcp -6 -l fake -A1 -L 10547 servers"); + NakedTestControl tc(opt); + uint32_t transid = 123; + boost::shared_ptr<Pkt6> pkt6(new Pkt6(DHCPV6_SOLICIT, transid)); + // Set packet's parameters. + tc.setDefaults6(pkt6); + // Validate if parameters have been set correctly. + EXPECT_EQ(tc.fake_sock_.iface_->getName(), pkt6->getIface()); + EXPECT_EQ(tc.socket_.ifindex_, pkt6->getIndex()); + EXPECT_EQ(DHCP6_CLIENT_PORT, pkt6->getLocalPort()); + EXPECT_EQ(DHCP6_SERVER_PORT, pkt6->getRemotePort()); + EXPECT_EQ(tc.socket_.addr_, pkt6->getLocalAddr()); + EXPECT_EQ(asiolink::IOAddress("FF05::1:3"), pkt6->getRemoteAddr()); + // Packet should be relayed. + EXPECT_EQ(pkt6->relay_info_.size(), 1); + EXPECT_EQ(pkt6->relay_info_[0].hop_count_, 0); + EXPECT_EQ(pkt6->relay_info_[0].msg_type_, DHCPV6_RELAY_FORW); + EXPECT_EQ(pkt6->relay_info_[0].linkaddr_, tc.socket_.addr_); + EXPECT_EQ(pkt6->relay_info_[0].peeraddr_, tc.socket_.addr_); +} + +TEST_F(TestControlTest, Packet6RelayedWithRelayOpts) { + CommandOptions opt; + processCmdLine(opt, "perfdhcp -6 -l fake -A1 --or 1:32,00000E10 -L 10547 servers"); + NakedTestControl tc(opt); + uint32_t transid = 123; + boost::shared_ptr<Pkt6> pkt6(new Pkt6(DHCPV6_SOLICIT, transid)); + // Set packet's parameters. + tc.setDefaults6(pkt6); + // Validate if parameters have been set correctly. + EXPECT_EQ(tc.fake_sock_.iface_->getName(), pkt6->getIface()); + EXPECT_EQ(tc.socket_.ifindex_, pkt6->getIndex()); + EXPECT_EQ(DHCP6_CLIENT_PORT, pkt6->getLocalPort()); + EXPECT_EQ(DHCP6_SERVER_PORT, pkt6->getRemotePort()); + EXPECT_EQ(tc.socket_.addr_, pkt6->getLocalAddr()); + EXPECT_EQ(asiolink::IOAddress("FF05::1:3"), pkt6->getRemoteAddr()); + // Packet should be relayed. + EXPECT_EQ(pkt6->relay_info_.size(), 1); + EXPECT_EQ(pkt6->relay_info_[0].hop_count_, 0); + EXPECT_EQ(pkt6->relay_info_[0].msg_type_, DHCPV6_RELAY_FORW); + EXPECT_EQ(pkt6->relay_info_[0].linkaddr_, tc.socket_.addr_); + EXPECT_EQ(pkt6->relay_info_[0].peeraddr_, tc.socket_.addr_); + // Checking if relayed option is there. + OptionBuffer opt_data = pkt6->relay_info_[0].options_.find(32)->second->getData(); + EXPECT_EQ(4, opt_data.size()); + EXPECT_EQ("0x00000E10", pkt6->relay_info_[0].options_.find(32)->second->toHexString()); +} + +TEST_F(TestControlTest, Packet4Exchange) { + const int iterations_num = 100; + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -r 100 -n 10 -R 20 -L 10547 127.0.0.1"); + bool use_templates = false; + NakedTestControl tc(opt); + testPkt4Exchange(iterations_num, iterations_num, use_templates, tc); + + EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num * 2); // Discovery + Request + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::DO), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::DO), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RA), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RA), 0); +} + +TEST_F(TestControlTest, Packet4ExchangeFromTemplate) { + const int iterations_num = 100; + CommandOptions opt; + + processCmdLine(opt, "perfdhcp -l fake -r 100 -R 20 -n 20 -L 10547" + " -T " + getFullPath("discover-example.hex") + + " -T " + getFullPath("request4-example.hex") + + " 127.0.0.1"); + const int received_num = 10; + bool use_templates = true; + NakedTestControl tc(opt); + testPkt4Exchange(iterations_num, received_num, use_templates, tc); + + EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num + received_num); // Discovery + Request + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::DO), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::DO), received_num); + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RA), received_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RA), 0); +} + +TEST_F(TestControlTest, Packet6Exchange) { + const int iterations_num = 100; + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -6 -r 100 -n 10 -R 20 -L 10547 ::1"); + bool use_templates = false; + NakedTestControl tc(opt); + testPkt6Exchange(iterations_num, iterations_num, use_templates, tc); + + EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num * 2); // Solicit + Request + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::SA), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::SA), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RR), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RR), 0); +} + +TEST_F(TestControlTest, Packet6ExchangeFromTemplate) { + const int iterations_num = 100; + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -6 -r 100 -n 10 -R 20 -L 10547" + " -T " + getFullPath("solicit-example.hex") + + " -T " + getFullPath("request6-example.hex ::1")); + NakedTestControl tc(opt); + + // For the first 3 packets we are simulating responses from server. + // For other packets we don't so packet as 4,5,6 will be dropped and + // 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) exchanges. + // The test function generates server's responses and passes it to the + // TestControl class methods for processing. 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. + bool use_templates = true; + testPkt6Exchange(iterations_num, received_num, use_templates, tc); + + EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num + received_num); // Solicit + Advertise + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::SA), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::SA), received_num); + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RR), received_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RR), 0); +} + +TEST_F(TestControlTest, Packet6ExchangeAddressOnly) { + const int iterations_num = 100; + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -e address-only" + " -6 -r 100 -n 10 -R 20 -L 10547 ::1"); + // 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) exchanges. + // The test function generates server's responses and passes it to the + // TestControl class methods for processing. 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. + NakedTestControl tc(opt); + testPkt6Exchange(iterations_num, iterations_num, use_templates, tc); + + EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num * 2); // Solicit + Request + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::SA), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::SA), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RR), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RR), 0); +} + +TEST_F(TestControlTest, Packet6ExchangePrefixDelegation) { + const int iterations_num = 100; + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -e prefix-only" + " -6 -r 100 -n 10 -R 20 -L 10547 ::1"); + // 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) exchanges. + // The test function generates server's responses and passes it to the + // TestControl class methods for processing. 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. + NakedTestControl tc(opt); + testPkt6Exchange(iterations_num, iterations_num, use_templates, tc); + + EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num * 2); // Discovery + Request + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::SA), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::SA), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RR), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RR), 0); +} + +TEST_F(TestControlTest, Packet6ExchangeAddressAndPrefix) { + const int iterations_num = 100; + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -e address-and-prefix" + " -6 -r 100 -n 10 -R 20 -L 10547 ::1"); + // 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) exchanges. + // The test function generates server's responses and passes it to the + // TestControl class methods for processing. 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. + NakedTestControl tc(opt); + testPkt6Exchange(iterations_num, iterations_num, use_templates, tc); + + EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num * 2); // Solicit + Request + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::SA), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::SA), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RR), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RR), 0); +} + +TEST_F(TestControlTest, PacketTemplates) { + std::vector<uint8_t> template1(256); + std::string file1("test1.hex"); + std::vector<uint8_t> template2(233); + std::string file2("test2.hex"); + for (size_t i = 0; i < template1.size(); ++i) { + template1[i] = static_cast<uint8_t>(random() % 256); + } + for (size_t i = 0; i < template2.size(); ++i) { + template2[i] = static_cast<uint8_t>(random() % 256); + } + // 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 opt; + processCmdLine(opt, "perfdhcp -l 127.0.0.1" + " -T " + file1 + " -T " + file2 + " all"); + NakedTestControl tc(opt); + + tc.initPacketTemplates(); + TestControl::TemplateBuffer buf1; + TestControl::TemplateBuffer buf2; + buf1 = tc.getTemplateBuffer(0); + buf2 = tc.getTemplateBuffer(1); + ASSERT_EQ(template1.size(), buf1.size()); + ASSERT_EQ(template2.size(), buf2.size()); + EXPECT_TRUE(std::equal(template1.begin(), template1.end(), buf1.begin())); + EXPECT_TRUE(std::equal(template2.begin(), template2.end(), buf2.begin())); + + // Try to read template file with odd number of digits. + std::string file3("test3.hex"); + // Size of the file is 2 times larger than binary data size and it is always + // even number. Substracting 1 makes file size odd. + ASSERT_TRUE(createTemplateFile(file3, template1, template1.size() * 2 - 1)); + processCmdLine(opt, "perfdhcp -l 127.0.0.1 -T " + file3 + " all"); + EXPECT_THROW(tc.initPacketTemplates(), isc::OutOfRange); + + // Try to read empty file. + std::string file4("test4.hex"); + ASSERT_TRUE(createTemplateFile(file4, template2, 0)); + processCmdLine(opt, "perfdhcp -l 127.0.0.1 -T " + file4 + " all"); + EXPECT_THROW(tc.initPacketTemplates(), isc::OutOfRange); + + // Try reading file with non hexadecimal characters. + std::string file5("test5.hex"); + ASSERT_TRUE(createTemplateFile(file5, template1, template1.size() * 2, true)); + processCmdLine(opt, "perfdhcp -l 127.0.0.1 -T " + file5 + " all"); + EXPECT_THROW(tc.initPacketTemplates(), isc::BadValue); +} + +// This test verifies that DHCPv4 renew (DHCPREQUEST) messages can be +// sent for acquired leases. +TEST_F(TestControlTest, processRenew4) { + testSendRenewRelease4(DHCPREQUEST); +} + +// This test verifies that DHCPv4 release (DHCPRELEASE) messages can be +// sent for acquired leases. +TEST_F(TestControlTest, processRelease4) { + testSendRenewRelease4(DHCPRELEASE); +} + +// This test verifies that DHCPv6 Renew messages can be sent for acquired +// leases. +TEST_F(TestControlTest, processRenew6) { + testSendRenewRelease6(DHCPV6_RENEW); +} + +// This test verifies that DHCPv6 Release messages can be sent for acquired +// leases. +TEST_F(TestControlTest, processRelease6) { + testSendRenewRelease6(DHCPV6_RELEASE); +} + +// This test verifies that DHCPREQUEST is created correctly from the +// DHCPACK message. +TEST_F(TestControlTest, createRenew4) { + testCreateRenewRelease4(DHCPREQUEST); +} + +// This test verifies that DHCPRELEASE is created correctly from the +// DHCPACK message. +TEST_F(TestControlTest, createRelease4) { + testCreateRenewRelease4(DHCPRELEASE); +} + +// This test verifies that the DHCPV6 Renew message is created correctly +// and that it comprises all required options. +TEST_F(TestControlTest, createRenew6) { + testCreateRenewRelease6(DHCPV6_RENEW); +} + +// This test verifies that the DHCPv6 Release message is created correctly +// and that it comprises all required options. +TEST_F(TestControlTest, createRelease6) { + testCreateRenewRelease6(DHCPV6_RELEASE); +} + +// This test verifies that the counter of rejected leases in +// Solicit-Advertise message exchange works correctly +TEST_F(TestControlTest, rejectedLeasesAdv) { + testCountRejectedLeasesSolAdv(); +} + +// Test checks if sendDiscover really includes custom options +TEST_F(TestControlTest, sendDiscoverExtraOpts) { + // Important parameters here: + // -xT - save first packet of each type for templates (useful for packet inspection) + // -o 200,abcdef1234 - send option 200 with hex content: ab:cd:ef:12:34 + // -o 201,00 - send option 201 with hex content: 00 + CommandOptions opt; + processCmdLine(opt, "perfdhcp -4 -l fake -xT -L 10068" + " -o 200,abcdef1234 -o 201,00 -r 1 127.0.0.1"); + + // Create test control and set up some basic defaults. + NakedTestControl tc(opt); + tc.registerOptionFactories(); + NakedTestControl::IncrementalGeneratorPtr gen(new NakedTestControl::IncrementalGenerator()); + tc.setTransidGenerator(gen); + + // Make tc send the packet. The first packet of each type is saved in templates. + tc.sendDiscover4(); + + // Let's find the packet and see if it includes the right option. + auto pkt_it = tc.template_packets_v4_.find(DHCPDISCOVER); + ASSERT_TRUE(pkt_it != tc.template_packets_v4_.end()); + + checkOptions20x(pkt_it->second); +} + +// Test checks if regular packet exchange inserts the extra v4 options +// specified on command line. +TEST_F(TestControlTest, Packet4ExchangeExtraOpts) { + // Important parameters here: + // -xT - save first packet of each type for templates (useful for packet inspection) + // -o 200,abcdef1234 - send option 200 with hex content: ab:cd:ef:12:34 + // -o 201,00 - send option 201 with hex content: 00 + const int iterations_num = 1; + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -4 -o 200,abcdef1234 -o 201,00 " + "-r 100 -n 10 -R 20 -xT -L 10547 127.0.0.1"); + + NakedTestControl tc(opt); + tc.registerOptionFactories(); + + // Do the actual exchange. + testPkt4Exchange(iterations_num, iterations_num, false, tc); + + EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num * 2); // Discovery + Request + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::DO), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::DO), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RA), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RA), 0); + + // Check if Discover was recored and if it contains options 200 and 201. + auto disc = tc.template_packets_v4_.find(DHCPDISCOVER); + ASSERT_TRUE(disc != tc.template_packets_v4_.end()); + checkOptions20x(disc->second); + + // Check if Request was recored and if it contains options 200 and 201. + auto req = tc.template_packets_v4_.find(DHCPREQUEST); + ASSERT_TRUE(req != tc.template_packets_v4_.end()); + checkOptions20x(req->second); +} + +// Test checks if regular packet exchange inserts the extra v6 options +// specified on command line. +TEST_F(TestControlTest, Packet6ExchangeExtraOpts) { + // Important parameters here: + // -xT - save first packet of each type for templates (useful for packet inspection) + // -o 200,abcdef1234 - send option 200 with hex content: ab:cd:ef:12:34 + // -o 201,00 - send option 201 with hex content: 00 + const int iterations_num = 1; + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake" + " -6 -e address-only" + " -xT -o 200,abcdef1234 -o 201,00 " + " -r 100 -n 10 -R 20 -L 10547 ::1"); + + // Simulate the number of Solicit-Advertise-Request-Reply (SARR) exchanges. + // The test function generates server's responses and passes it to the + // TestControl class methods for processing. + // First packet of each type is recorded as a template packet. The check + // inspects this template to see if the expected options are really there. + NakedTestControl tc(opt); + testPkt6Exchange(iterations_num, iterations_num, false, tc); + + EXPECT_EQ(tc.fake_sock_.sent_cnt_, iterations_num * 2); // Solicit + Request + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::SA), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::SA), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getSentPacketsNum(ExchangeType::RR), iterations_num); + EXPECT_EQ(tc.stats_mgr_.getRcvdPacketsNum(ExchangeType::RR), 0); + + // Check if Solicit was recorded and if it contains options 200 and 201. + auto sol = tc.template_packets_v6_.find(DHCPV6_SOLICIT); + ASSERT_TRUE(sol != tc.template_packets_v6_.end()); + checkOptions20x(sol->second); + + // Check if Request was recorded and if it contains options 200 and 201. + auto req = tc.template_packets_v6_.find(DHCPV6_REQUEST); + ASSERT_TRUE(req != tc.template_packets_v6_.end()); + checkOptions20x(req->second); +} + +// Test checks if multiple v4 PRL options can be sent. They should be merged +// into a single PRL option by perfdhcp. +TEST_F(TestControlTest, sendDiscoverMultiplePRLs) { + // Important parameters here: + // -o 55,1234 - send option 55 with hex content '1234' + // -o 55,abcd - send option 55 with hex content 'abcd' + CommandOptions opt; + processCmdLine( + opt, "perfdhcp -4 -l fake -o 55,1234 -o 55,abcd -r 1 -xT 127.0.0.1"); + + // Create test control and set up some basic defaults. + NakedTestControl tc(opt); + tc.registerOptionFactories(); + NakedTestControl::IncrementalGeneratorPtr gen( + boost::make_shared<NakedTestControl::IncrementalGenerator>()); + tc.setTransidGenerator(gen); + + // Send the packet. + tc.sendDiscover4(); + + // Let's find the packet and see if it includes the right option. + auto const pkt_it(tc.template_packets_v4_.find(DHCPDISCOVER)); + ASSERT_TRUE(pkt_it != tc.template_packets_v4_.end()); + + checkOptions55(pkt_it->second, + { + // Added to all perfdhcp egress packets by default + DHO_SUBNET_MASK, + DHO_BROADCAST_ADDRESS, + DHO_TIME_OFFSET, + DHO_ROUTERS, + DHO_DOMAIN_NAME, + DHO_DOMAIN_NAME_SERVERS, + DHO_HOST_NAME, + // Explicitly added in this test + 0x12, + 0x34, + 0xab, + 0xcd, + }); +} + +// This test checks if HA failure can be simulated using -y and -Y options with DHCPv4. +TEST_F(TestControlTest, haFailure4) { + CommandOptions opt; + processCmdLine(opt, "perfdhcp -l fake -r 1 -n 1 -R 2 -y 10 -Y 0 -L 10547 127.0.0.1"); + NakedTestControl tc(opt); + + tc.sendPackets(1); // Send one packet. It should have secs set to 1. + sleep(1); // wait a second... + tc.sendPackets(1); // and send another packet. This should have secs set to 2. + + EXPECT_EQ(tc.fake_sock_.sent_cnt_, 2); // Make sure the stats are up. + ASSERT_EQ(tc.fake_sock_.sent_pkts4_.size(), 2); // And the packets were captured. + Pkt4Ptr dis1 = tc.fake_sock_.sent_pkts4_[0]; + Pkt4Ptr dis2 = tc.fake_sock_.sent_pkts4_[1]; + ASSERT_TRUE(dis1); + ASSERT_TRUE(dis2); + + EXPECT_EQ(dis1->getSecs(), 1); // Make sure it has secs set to 1. + EXPECT_GT(dis2->getSecs(), 1); // Should be 2, but we want to avoid rare cases when the test + // could fall exactly on the second boundary, so checking for + // greater than 1. +} + +// This test checks if HA failure can be simulated using -y and -Y options with DHCPv6. +TEST_F(TestControlTest, haFailure6) { + CommandOptions opt; + processCmdLine(opt, "perfdhcp -6 -l fake -r 1 -n 1 -R 2 -y 10 -Y 0 -L 10547 all"); + NakedTestControl tc(opt); + + tc.sendPackets(1); // Send one packet. It should have secs set to 1. + sleep(1); // wait a second... + tc.sendPackets(1); // and send another packet. This should have secs set to 2. + + EXPECT_EQ(tc.fake_sock_.sent_cnt_, 2); // Make sure the stats are up. + ASSERT_EQ(tc.fake_sock_.sent_pkts6_.size(), 2); // And the packets were captured. + Pkt6Ptr sol1 = tc.fake_sock_.sent_pkts6_[0]; + Pkt6Ptr sol2 = tc.fake_sock_.sent_pkts6_[1]; + ASSERT_TRUE(sol1); + ASSERT_TRUE(sol2); + OptionUint16Ptr elapsed1(boost::dynamic_pointer_cast<OptionUint16>(sol1->getOption(D6O_ELAPSED_TIME))); + OptionUint16Ptr elapsed2(boost::dynamic_pointer_cast<OptionUint16>(sol2->getOption(D6O_ELAPSED_TIME))); + ASSERT_TRUE(elapsed1); + ASSERT_TRUE(elapsed2); + + EXPECT_EQ(elapsed1->getValue(), 100); + EXPECT_GT(elapsed2->getValue(), 100); +} diff --git a/src/bin/perfdhcp/tests/testdata/Makefile.am b/src/bin/perfdhcp/tests/testdata/Makefile.am new file mode 100644 index 0000000..19cf25d --- /dev/null +++ b/src/bin/perfdhcp/tests/testdata/Makefile.am @@ -0,0 +1,5 @@ +SUBDIRS = . + +EXTRA_DIST = discover-example.hex request4-example.hex +EXTRA_DIST += solicit-example.hex request6-example.hex +EXTRA_DIST += mac-list.txt relay4-list.txt relay6-list.txt diff --git a/src/bin/perfdhcp/tests/testdata/Makefile.in b/src/bin/perfdhcp/tests/testdata/Makefile.in new file mode 100644 index 0000000..299c09b --- /dev/null +++ b/src/bin/perfdhcp/tests/testdata/Makefile.in @@ -0,0 +1,731 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/bin/perfdhcp/tests/testdata +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \ + $(top_srcdir)/m4macros/ax_cpp11.m4 \ + $(top_srcdir)/m4macros/ax_cpp20.m4 \ + $(top_srcdir)/m4macros/ax_crypto.m4 \ + $(top_srcdir)/m4macros/ax_find_library.m4 \ + $(top_srcdir)/m4macros/ax_gssapi.m4 \ + $(top_srcdir)/m4macros/ax_gtest.m4 \ + $(top_srcdir)/m4macros/ax_isc_rpath.m4 \ + $(top_srcdir)/m4macros/ax_netconf.m4 \ + $(top_srcdir)/m4macros/libtool.m4 \ + $(top_srcdir)/m4macros/ltoptions.m4 \ + $(top_srcdir)/m4macros/ltsugar.m4 \ + $(top_srcdir)/m4macros/ltversion.m4 \ + $(top_srcdir)/m4macros/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ASCIIDOC = @ASCIIDOC@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_INCLUDES = @BOOST_INCLUDES@ +BOOST_LIBS = @BOOST_LIBS@ +BOTAN_TOOL = @BOTAN_TOOL@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONTRIB_DIR = @CONTRIB_DIR@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CRYPTO_CFLAGS = @CRYPTO_CFLAGS@ +CRYPTO_INCLUDES = @CRYPTO_INCLUDES@ +CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@ +CRYPTO_LIBS = @CRYPTO_LIBS@ +CRYPTO_PACKAGE = @CRYPTO_PACKAGE@ +CRYPTO_RPATH = @CRYPTO_RPATH@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@ +DISTCHECK_CONTRIB_CONFIGURE_FLAG = @DISTCHECK_CONTRIB_CONFIGURE_FLAG@ +DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@ +DISTCHECK_GSSAPI_CONFIGURE_FLAG = @DISTCHECK_GSSAPI_CONFIGURE_FLAG@ +DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ +DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@ +DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG = @DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG@ +DISTCHECK_LIBYANG_CONFIGURE_FLAG = @DISTCHECK_LIBYANG_CONFIGURE_FLAG@ +DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@ +DISTCHECK_MYSQL_CONFIGURE_FLAG = @DISTCHECK_MYSQL_CONFIGURE_FLAG@ +DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@ +DISTCHECK_PGSQL_CONFIGURE_FLAG = @DISTCHECK_PGSQL_CONFIGURE_FLAG@ +DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@ +DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG = @DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG@ +DISTCHECK_SYSREPO_CONFIGURE_FLAG = @DISTCHECK_SYSREPO_CONFIGURE_FLAG@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GENHTML = @GENHTML@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GTEST_CONFIG = @GTEST_CONFIG@ +GTEST_INCLUDES = @GTEST_INCLUDES@ +GTEST_LDADD = @GTEST_LDADD@ +GTEST_LDFLAGS = @GTEST_LDFLAGS@ +GTEST_SOURCE = @GTEST_SOURCE@ +HAVE_NETCONF = @HAVE_NETCONF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KEA_CXXFLAGS = @KEA_CXXFLAGS@ +KEA_SRCID = @KEA_SRCID@ +KRB5_CONFIG = @KRB5_CONFIG@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBYANGCPP_CPPFLAGS = @LIBYANGCPP_CPPFLAGS@ +LIBYANGCPP_INCLUDEDIR = @LIBYANGCPP_INCLUDEDIR@ +LIBYANGCPP_LIBS = @LIBYANGCPP_LIBS@ +LIBYANGCPP_PREFIX = @LIBYANGCPP_PREFIX@ +LIBYANGCPP_VERSION = @LIBYANGCPP_VERSION@ +LIBYANG_CPPFLAGS = @LIBYANG_CPPFLAGS@ +LIBYANG_INCLUDEDIR = @LIBYANG_INCLUDEDIR@ +LIBYANG_LIBS = @LIBYANG_LIBS@ +LIBYANG_PREFIX = @LIBYANG_PREFIX@ +LIBYANG_VERSION = @LIBYANG_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@ +LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LIBS = @MYSQL_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PACKAGE_VERSION_TYPE = @PACKAGE_VERSION_TYPE@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PDFLATEX = @PDFLATEX@ +PERL = @PERL@ +PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@ +PGSQL_LIBS = @PGSQL_LIBS@ +PKGPYTHONDIR = @PKGPYTHONDIR@ +PKG_CONFIG = @PKG_CONFIG@ +PLANTUML = @PLANTUML@ +PREMIUM_DIR = @PREMIUM_DIR@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SEP = @SEP@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SPHINXBUILD = @SPHINXBUILD@ +SRPD_PLUGINS_PATH = @SRPD_PLUGINS_PATH@ +SR_PLUGINS_PATH = @SR_PLUGINS_PATH@ +SR_REPO_PATH = @SR_REPO_PATH@ +STRIP = @STRIP@ +SYSREPOCPP_CPPFLAGS = @SYSREPOCPP_CPPFLAGS@ +SYSREPOCPP_INCLUDEDIR = @SYSREPOCPP_INCLUDEDIR@ +SYSREPOCPP_LIBS = @SYSREPOCPP_LIBS@ +SYSREPOCPP_PREFIX = @SYSREPOCPP_PREFIX@ +SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@ +SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@ +SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@ +SYSREPO_LIBS = @SYSREPO_LIBS@ +SYSREPO_PREFIX = @SYSREPO_PREFIX@ +SYSREPO_VERSION = @SYSREPO_VERSION@ +USE_LCOV = @USE_LCOV@ +VALGRIND = @VALGRIND@ +VERSION = @VERSION@ +WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@ +YACC = @YACC@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . +EXTRA_DIST = discover-example.hex request4-example.hex \ + solicit-example.hex request6-example.hex mac-list.txt \ + relay4-list.txt relay6-list.txt +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/bin/perfdhcp/tests/testdata/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/bin/perfdhcp/tests/testdata/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/bin/perfdhcp/tests/testdata/discover-example.hex b/src/bin/perfdhcp/tests/testdata/discover-example.hex new file mode 100644 index 0000000..9a6e5ea --- /dev/null +++ b/src/bin/perfdhcp/tests/testdata/discover-example.hex @@ -0,0 +1 @@ +01010601008b45d200000000000000000000000000000000ac100102000c0102030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000638253633501013707011c02030f060cff
\ No newline at end of file diff --git a/src/bin/perfdhcp/tests/testdata/mac-list.txt b/src/bin/perfdhcp/tests/testdata/mac-list.txt new file mode 100644 index 0000000..e9e30e0 --- /dev/null +++ b/src/bin/perfdhcp/tests/testdata/mac-list.txt @@ -0,0 +1,4 @@ +11:22:33:44:55:66 +11:22:33:44:55:77 +11:22:33:44:55:88 +11:22:33:44:55:99 diff --git a/src/bin/perfdhcp/tests/testdata/relay4-list.txt b/src/bin/perfdhcp/tests/testdata/relay4-list.txt new file mode 100644 index 0000000..6d3db81 --- /dev/null +++ b/src/bin/perfdhcp/tests/testdata/relay4-list.txt @@ -0,0 +1,5 @@ +100.95.0.1 +20.86.12.1 +101.64.4.1 +1.86.0.1 +92.86.238.1 diff --git a/src/bin/perfdhcp/tests/testdata/relay6-list.txt b/src/bin/perfdhcp/tests/testdata/relay6-list.txt new file mode 100644 index 0000000..ce98e94 --- /dev/null +++ b/src/bin/perfdhcp/tests/testdata/relay6-list.txt @@ -0,0 +1,2 @@ +3000::1 +fe80::6e2b:59ff:fe94:19d1 diff --git a/src/bin/perfdhcp/tests/testdata/request4-example.hex b/src/bin/perfdhcp/tests/testdata/request4-example.hex new file mode 100644 index 0000000..32447d6 --- /dev/null +++ b/src/bin/perfdhcp/tests/testdata/request4-example.hex @@ -0,0 +1 @@ +01010601007b23f800000000000000000000000000000000ac100102000c0102030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000638253633204ac1001813501033604ac1001013707011c02030f060cff
\ No newline at end of file diff --git a/src/bin/perfdhcp/tests/testdata/request6-example.hex b/src/bin/perfdhcp/tests/testdata/request6-example.hex new file mode 100644 index 0000000..1e3e76f --- /dev/null +++ b/src/bin/perfdhcp/tests/testdata/request6-example.hex @@ -0,0 +1 @@ +03da30c60001000e0001000117cf8e76000c010203060002000e0001000117cf8a5c080027a87b3400030028000000010000000a0000000e0005001820010db800010000000000000001b568000000be000000c8000800020000
\ No newline at end of file diff --git a/src/bin/perfdhcp/tests/testdata/solicit-example.hex b/src/bin/perfdhcp/tests/testdata/solicit-example.hex new file mode 100644 index 0000000..41c5ad3 --- /dev/null +++ b/src/bin/perfdhcp/tests/testdata/solicit-example.hex @@ -0,0 +1 @@ +015f4e650001000e0001000117cf8e76000c010203040003000c0000000100000e01000015180006000400170018000800020000
\ No newline at end of file |