summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xconfigure.ac14
-rw-r--r--tests/.gitignore50
-rw-r--r--tests/Makefile.am197
-rw-r--r--tests/bgpd.tests/Makefile.am7
-rw-r--r--tests/bgpd.tests/aspathtest.exp76
-rw-r--r--tests/bgpd.tests/ecommtest.exp13
-rw-r--r--tests/bgpd.tests/testbgpcap.exp51
-rw-r--r--tests/bgpd.tests/testbgpmpath.exp12
-rw-r--r--tests/bgpd.tests/testbgpmpattr.exp38
-rw-r--r--tests/bgpd/test_aspath.c (renamed from tests/aspath_test.c)0
-rw-r--r--tests/bgpd/test_aspath.py79
-rw-r--r--tests/bgpd/test_capability.c (renamed from tests/bgp_capability_test.c)0
-rw-r--r--tests/bgpd/test_capability.py47
-rw-r--r--tests/bgpd/test_ecommunity.c (renamed from tests/ecommunity_test.c)0
-rw-r--r--tests/bgpd/test_ecommunity.py9
-rw-r--r--tests/bgpd/test_mp_attr.c (renamed from tests/bgp_mp_attr_test.c)0
-rw-r--r--tests/bgpd/test_mp_attr.py33
-rw-r--r--tests/bgpd/test_mpath.c (renamed from tests/bgp_mpath_test.c)0
-rw-r--r--tests/bgpd/test_mpath.py9
-rw-r--r--tests/config/unix.exp102
-rw-r--r--tests/global-conf.exp0
-rw-r--r--tests/helpers/c/main.c (renamed from tests/main.c)0
-rw-r--r--tests/helpers/c/prng.c (renamed from tests/prng.c)0
-rw-r--r--tests/helpers/c/prng.h (renamed from tests/prng.h)0
-rw-r--r--tests/helpers/c/tests.h (renamed from tests/tests.h)0
-rw-r--r--tests/helpers/python/frrsix.py80
-rw-r--r--tests/helpers/python/frrtest.py177
-rw-r--r--tests/lib/bgpd.exp0
-rw-r--r--tests/lib/cli/common_cli.c (renamed from tests/common-cli.c)2
-rw-r--r--tests/lib/cli/common_cli.h (renamed from tests/common-cli.h)0
-rw-r--r--tests/lib/cli/test_cli.c (renamed from tests/test-cli.c)2
-rw-r--r--tests/lib/cli/test_cli.in (renamed from tests/testcli.in)0
-rw-r--r--tests/lib/cli/test_cli.py4
-rw-r--r--tests/lib/cli/test_cli.refout (renamed from tests/testcli.refout)0
-rw-r--r--tests/lib/cli/test_commands.c (renamed from tests/test-commands.c)0
-rw-r--r--tests/lib/cli/test_commands.in (renamed from tests/testcommands.in)0
-rw-r--r--tests/lib/cli/test_commands.py8
-rw-r--r--tests/lib/cli/test_commands.refout (renamed from tests/testcommands.refout)0
-rw-r--r--tests/lib/libfrr.exp0
-rw-r--r--tests/lib/test_buffer.c (renamed from tests/test-buffer.c)0
-rw-r--r--tests/lib/test_checksum.c (renamed from tests/test-checksum.c)0
-rw-r--r--tests/lib/test_heavy.c (renamed from tests/heavy.c)0
-rw-r--r--tests/lib/test_heavy_thread.c (renamed from tests/heavy-thread.c)0
-rw-r--r--tests/lib/test_heavy_wq.c (renamed from tests/heavy-wq.c)0
-rw-r--r--tests/lib/test_memory.c (renamed from tests/test-memory.c)0
-rw-r--r--tests/lib/test_nexthop_iter.c (renamed from tests/test-nexthop-iter.c)0
-rw-r--r--tests/lib/test_nexthop_iter.py7
-rw-r--r--tests/lib/test_privs.c (renamed from tests/test-privs.c)0
-rw-r--r--tests/lib/test_segv.c (renamed from tests/test-segv.c)0
-rw-r--r--tests/lib/test_sig.c (renamed from tests/test-sig.c)0
-rw-r--r--tests/lib/test_srcdest_table.c (renamed from tests/test-srcdest-table.c)0
-rw-r--r--tests/lib/test_srcdest_table.py6
-rw-r--r--tests/lib/test_stream.c (renamed from tests/test-stream.c)0
-rw-r--r--tests/lib/test_stream.py4
-rw-r--r--tests/lib/test_stream.refout8
-rw-r--r--tests/lib/test_table.c (renamed from tests/table_test.c)0
-rw-r--r--tests/lib/test_table.py10
-rw-r--r--tests/lib/test_timer_correctness.c (renamed from tests/test-timer-correctness.c)0
-rw-r--r--tests/lib/test_timer_correctness.py6
-rw-r--r--tests/lib/test_timer_performance.c (renamed from tests/test-timer-performance.c)0
-rw-r--r--tests/libfrr.tests/Makefile.am6
-rw-r--r--tests/libfrr.tests/tabletest.exp9
-rw-r--r--tests/libfrr.tests/test-timer-correctness.exp7
-rw-r--r--tests/libfrr.tests/testcli.exp23
-rw-r--r--tests/libfrr.tests/testcommands.exp31
-rw-r--r--tests/libfrr.tests/testnexthopiter.exp8
-rw-r--r--tests/libfrr.tests/teststream.exp28
-rw-r--r--tests/libzebra.tests/test-srcdest-table.exp7
-rw-r--r--tests/runtests.py6
69 files changed, 645 insertions, 531 deletions
diff --git a/configure.ac b/configure.ac
index 4eebe67bb3..1436b2fc7c 100755
--- a/configure.ac
+++ b/configure.ac
@@ -1574,18 +1574,6 @@ dnl ----------
CONFDATE=`date '+%Y%m%d'`
AC_SUBST(CONFDATE)
-dnl -------
-dnl DejaGNU
-dnl -------
-if test x"$DEJAGNU" = x
-then
- DEJAGNU="\$(top_srcdir)/tests/global-conf.exp"
-fi
-RUNTESTDEFAULTFLAGS="-x --tool \$\$tool"
-
-AC_SUBST(DEJAGNU)
-AC_SUBST(RUNTESTDEFAULTFLAGS)
-
dnl ------------------------------
dnl set paths for state directory
dnl ------------------------------
@@ -1687,8 +1675,6 @@ AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile
ospf6d/Makefile ldpd/Makefile isisd/Makefile vtysh/Makefile
doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile
pimd/Makefile
- tests/bgpd.tests/Makefile
- tests/libfrr.tests/Makefile
redhat/Makefile
tools/Makefile
cumulus/Makefile
diff --git a/tests/.gitignore b/tests/.gitignore
index 3002b27149..bab3385da2 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -3,6 +3,7 @@ Makefile.in
*.o
tags
TAGS
+.cache
.deps
.nfs*
*~
@@ -14,28 +15,31 @@ TAGS
*.log
*.sum
*.xml
+*.pyc
.arch-inventory
.arch-ids
-aspathtest
-ecommtest
-heavy
-heavythread
-heavywq
-tabletest
-test-timer-correctness
-test-timer-performance
-testbgpcap
-testbgpmpath
-testbgpmpattr
-testbuffer
-testchecksum
-testcli
-testmemory
-testprivs
-testsegv
-testsig
-teststream
-testnexthopiter
-testcommands
-test-commands-defun.c
-site.exp
+__pycache__
+.dirstamp
+/bgpd/test_aspath
+/bgpd/test_capability
+/bgpd/test_ecommunity
+/bgpd/test_mp_attr
+/bgpd/test_mpath
+/lib/cli/test_cli
+/lib/cli/test_commands
+/lib/cli/test_commands_defun.c
+/lib/test_buffer
+/lib/test_checksum
+/lib/test_heavy
+/lib/test_heavy_thread
+/lib/test_heavy_wq
+/lib/test_memory
+/lib/test_nexthop_iter
+/lib/test_privs
+/lib/test_srcdest_table
+/lib/test_segv
+/lib/test_sig
+/lib/test_stream
+/lib/test_table
+/lib/test_timer_correctness
+/lib/test_timer_performance
diff --git a/tests/Makefile.am b/tests/Makefile.am
index bee9feaf1e..922ec37a24 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,99 +1,148 @@
-AUTOMAKE_OPTIONS = dejagnu
-DEJATOOL = libfrr
+PYTHON ?= python
-SUBDIRS = \
- bgpd.tests \
- libfrr.tests
-
-EXTRA_DIST = \
- config/unix.exp \
- lib/bgpd.exp \
- lib/libfrr.exp \
- global-conf.exp \
- testcommands.in \
- testcommands.refout \
- testcli.in \
- testcli.refout
-
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
+AUTOMAKE_OPTIONS = subdir-objects
+AM_CPPFLAGS = \
+ -I.. \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/lib \
+ -I$(top_builddir)/lib \
+ -I$(top_srcdir)/tests/helpers/c \
+ -I$(top_builddir)/tests/helpers/c \
+ -O
DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\"
if BGPD
-TESTS_BGPD = aspathtest testbgpcap ecommtest testbgpmpattr testbgpmpath
-DEJATOOL += bgpd
+TESTS_BGPD = \
+ bgpd/test_aspath \
+ bgpd/test_capability \
+ bgpd/test_ecommunity \
+ bgpd/test_mp_attr \
+ bgpd/test_mpath
else
TESTS_BGPD =
endif
if ENABLE_BGP_VNC
-BGP_VNC_RFP_LIB=@top_builddir@/$(LIBRFP)/librfp.a
+BGP_VNC_RFP_LIB=@top_builddir@/$(LIBRFP)/librfp.a
else
BGP_VNC_RFP_LIB =
endif
-check_PROGRAMS = testsig testsegv testbuffer testmemory heavy heavywq heavythread \
- testprivs teststream testchecksum tabletest testnexthopiter \
- testcommands test-timer-correctness test-timer-performance \
- testcli \
- test-srcdest-table \
- $(TESTS_BGPD)
+check_PROGRAMS = \
+ lib/test_buffer \
+ lib/test_checksum \
+ lib/test_heavy_thread \
+ lib/test_heavy_wq \
+ lib/test_heavy \
+ lib/test_memory \
+ lib/test_nexthop_iter \
+ lib/test_privs \
+ lib/test_srcdest_table \
+ lib/test_segv \
+ lib/test_sig \
+ lib/test_stream \
+ lib/test_table \
+ lib/test_timer_correctness \
+ lib/test_timer_performance \
+ lib/cli/test_cli \
+ lib/cli/test_commands \
+ $(TESTS_BGPD)
../vtysh/vtysh_cmd.c:
$(MAKE) -C ../vtysh vtysh_cmd.c
-test-commands-defun.c: ../vtysh/vtysh_cmd.c
+lib/cli/test_commands_defun.c: ../vtysh/vtysh_cmd.c
sed \
-e 's/"vtysh\.h"/"tests.h"/' \
-e 's/vtysh_init_cmd/test_init_cmd/' \
-e 's/VTYSH_[A-Z][A-Z_0-9]*/0/g' \
< ../vtysh/vtysh_cmd.c \
- > test-commands-defun.c
+ > "$@"
+
+BUILT_SOURCES = lib/cli/test_commands_defun.c
-BUILT_SOURCES = test-commands-defun.c
-noinst_HEADERS = prng.h tests.h common-cli.h
+noinst_HEADERS = \
+ ./helpers/c/prng.h \
+ ./helpers/c/tests.h \
+ ./lib/cli/common_cli.h
-testcli_SOURCES = test-cli.c common-cli.c
-testsig_SOURCES = test-sig.c
-testsegv_SOURCES = test-segv.c
-testbuffer_SOURCES = test-buffer.c
-testmemory_SOURCES = test-memory.c
-testprivs_SOURCES = test-privs.c
-teststream_SOURCES = test-stream.c
-heavy_SOURCES = heavy.c main.c
-heavywq_SOURCES = heavy-wq.c main.c
-heavythread_SOURCES = heavy-thread.c main.c
-aspathtest_SOURCES = aspath_test.c
-testbgpcap_SOURCES = bgp_capability_test.c
-ecommtest_SOURCES = ecommunity_test.c
-testbgpmpattr_SOURCES = bgp_mp_attr_test.c
-testchecksum_SOURCES = test-checksum.c
-testbgpmpath_SOURCES = bgp_mpath_test.c
-tabletest_SOURCES = table_test.c
-testnexthopiter_SOURCES = test-nexthop-iter.c prng.c
-testcommands_SOURCES = test-commands-defun.c test-commands.c prng.c
-test_timer_correctness_SOURCES = test-timer-correctness.c prng.c
-test_timer_performance_SOURCES = test-timer-performance.c prng.c
-test_srcdest_table_SOURCES = test-srcdest-table.c prng.c
+lib_test_buffer_SOURCES = lib/test_buffer.c
+lib_test_checksum_SOURCES = lib/test_checksum.c
+lib_test_heavy_thread_SOURCES = lib/test_heavy_thread.c helpers/c/main.c
+lib_test_heavy_wq_SOURCES = lib/test_heavy_wq.c helpers/c/main.c
+lib_test_heavy_SOURCES = lib/test_heavy.c helpers/c/main.c
+lib_test_memory_SOURCES = lib/test_memory.c
+lib_test_nexthop_iter_SOURCES = lib/test_nexthop_iter.c helpers/c/prng.c
+lib_test_privs_SOURCES = lib/test_privs.c
+lib_test_srcdest_table_SOURCES = lib/test_srcdest_table.c \
+ helpers/c/prng.c
+lib_test_segv_SOURCES = lib/test_segv.c
+lib_test_sig_SOURCES = lib/test_sig.c
+lib_test_stream_SOURCES = lib/test_stream.c
+lib_test_table_SOURCES = lib/test_table.c
+lib_test_timer_correctness_SOURCES = lib/test_timer_correctness.c \
+ helpers/c/prng.c
+lib_test_timer_performance_SOURCES = lib/test_timer_performance.c \
+ helpers/c/prng.c
+lib_cli_test_cli_SOURCES = lib/cli/test_cli.c lib/cli/common_cli.c
+lib_cli_test_commands_SOURCES = lib/cli/test_commands_defun.c \
+ lib/cli/test_commands.c \
+ helpers/c/prng.c
+bgpd_test_aspath_SOURCES = bgpd/test_aspath.c
+bgpd_test_capability_SOURCES = bgpd/test_capability.c
+bgpd_test_ecommunity_SOURCES = bgpd/test_ecommunity.c
+bgpd_test_mp_attr_SOURCES = bgpd/test_mp_attr.c
+bgpd_test_mpath_SOURCES = bgpd/test_mpath.c
+
+ALL_TESTS_LDADD = ../lib/libfrr.la @LIBCAP@
+BGP_TEST_LDADD = ../bgpd/libbgp.a $(BGP_VNC_RFP_LIB) $(ALL_TESTS_LDADD) -lm
+
+lib_test_buffer_LDADD = $(ALL_TESTS_LDADD)
+lib_test_checksum_LDADD = $(ALL_TESTS_LDADD)
+lib_test_heavy_thread_LDADD = $(ALL_TESTS_LDADD) -lm
+lib_test_heavy_wq_LDADD = $(ALL_TESTS_LDADD) -lm
+lib_test_heavy_LDADD = $(ALL_TESTS_LDADD) -lm
+lib_test_memory_LDADD = $(ALL_TESTS_LDADD)
+lib_test_nexthop_iter_LDADD = $(ALL_TESTS_LDADD)
+lib_test_privs_LDADD = $(ALL_TESTS_LDADD)
+lib_test_srcdest_table_LDADD = $(ALL_TESTS_LDADD)
+lib_test_segv_LDADD = $(ALL_TESTS_LDADD)
+lib_test_sig_LDADD = $(ALL_TESTS_LDADD)
+lib_test_stream_LDADD = $(ALL_TESTS_LDADD)
+lib_test_table_LDADD = $(ALL_TESTS_LDADD) -lm
+lib_test_timer_correctness_LDADD = $(ALL_TESTS_LDADD)
+lib_test_timer_performance_LDADD = $(ALL_TESTS_LDADD)
+lib_cli_test_cli_LDADD = $(ALL_TESTS_LDADD)
+lib_cli_test_commands_LDADD = $(ALL_TESTS_LDADD)
+bgpd_test_aspath_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_capability_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_ecommunity_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_mp_attr_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_mpath_LDADD = $(BGP_TEST_LDADD)
+
+EXTRA_DIST = \
+ runtests.py \
+ bgpd/test_aspath.py \
+ bgpd/test_capability.py \
+ bgpd/test_ecommunity.py \
+ bgpd/test_mp_attr.py \
+ bgpd/test_mpath.py \
+ helpers/python/frrsix.py \
+ helpers/python/frrtest.py \
+ lib/cli/test_commands.in \
+ lib/cli/test_commands.py \
+ lib/cli/test_commands.refout \
+ lib/cli/test_cli.in \
+ lib/cli/test_cli.py \
+ lib/cli/test_cli.refout \
+ lib/test_nexthop_iter.py \
+ lib/test_srcdest_table.py \
+ lib/test_stream.py \
+ lib/test_stream.refout \
+ lib/test_table.py \
+ lib/test_timer_correctness.py
-testcli_LDADD = ../lib/libfrr.la @LIBCAP@
-testsig_LDADD = ../lib/libfrr.la @LIBCAP@
-testsegv_LDADD = ../lib/libfrr.la @LIBCAP@
-testbuffer_LDADD = ../lib/libfrr.la @LIBCAP@
-testmemory_LDADD = ../lib/libfrr.la @LIBCAP@
-testprivs_LDADD = ../lib/libfrr.la @LIBCAP@
-teststream_LDADD = ../lib/libfrr.la @LIBCAP@
-heavy_LDADD = ../lib/libfrr.la @LIBCAP@ -lm
-heavywq_LDADD = ../lib/libfrr.la @LIBCAP@ -lm
-heavythread_LDADD = ../lib/libfrr.la @LIBCAP@ -lm
-aspathtest_LDADD = ../bgpd/libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ -lm
-testbgpcap_LDADD = ../bgpd/libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ -lm
-ecommtest_LDADD = ../bgpd/libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ -lm
-testbgpmpattr_LDADD = ../bgpd/libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ -lm
-testchecksum_LDADD = ../lib/libfrr.la @LIBCAP@
-testbgpmpath_LDADD = ../bgpd/libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ -lm
-tabletest_LDADD = ../lib/libfrr.la @LIBCAP@ -lm
-testnexthopiter_LDADD = ../lib/libfrr.la @LIBCAP@
-testcommands_LDADD = ../lib/libfrr.la @LIBCAP@
-test_timer_correctness_LDADD = ../lib/libfrr.la @LIBCAP@
-test_timer_performance_LDADD = ../lib/libfrr.la @LIBCAP@
-test_srcdest_table_LDADD = ../lib/libfrr.la @LIBCAP@
+.PHONY: tests.xml
+tests.xml: $(check_PROGRAMS)
+ $(PYTHON) runtests.py --junitxml=$@ -v
+check: tests.xml
diff --git a/tests/bgpd.tests/Makefile.am b/tests/bgpd.tests/Makefile.am
deleted file mode 100644
index 5900186cf5..0000000000
--- a/tests/bgpd.tests/Makefile.am
+++ /dev/null
@@ -1,7 +0,0 @@
-EXTRA_DIST = \
- aspathtest.exp \
- ecommtest.exp \
- testbgpcap.exp \
- testbgpmpath.exp \
- testbgpmpattr.exp
-
diff --git a/tests/bgpd.tests/aspathtest.exp b/tests/bgpd.tests/aspathtest.exp
deleted file mode 100644
index f5f262f80a..0000000000
--- a/tests/bgpd.tests/aspathtest.exp
+++ /dev/null
@@ -1,76 +0,0 @@
-set timeout 10
-set testprefix "aspathtest "
-set aborted 0
-set color 1
-
-spawn sh -c "exec ./aspathtest 2>/dev/null"
-
-# proc onetest { test_name note start } {
-# proc headerline { line } {
-
-set parserno 0
-proc parsertest { test_name } {
- global parserno
- headerline "test $parserno"
- onetest "parse $test_name" " ($parserno)" "$test_name:"
- onetest "parse $test_name +empty_prepend" " (#$parserno)" "empty prepend $test_name:"
- incr parserno 1
-}
-set attrno 0
-proc attrtest { test_name } {
- global attrno
- headerline "aspath_attr test $attrno"
- onetest "attr $test_name" " (#$attrno)" "$test_name"
- incr attrno 1
-}
-
-
-parsertest "seq1"
-parsertest "seq2"
-parsertest "seq3"
-parsertest "seqset"
-parsertest "seqset2"
-parsertest "multi"
-parsertest "confed"
-parsertest "confed2"
-parsertest "confset"
-parsertest "confmulti"
-parsertest "seq4"
-parsertest "tripleseq1"
-parsertest "someprivate"
-parsertest "allprivate"
-parsertest "long"
-parsertest "seq1extra"
-parsertest "empty"
-parsertest "redundantset"
-parsertest "reconcile_lead_asp"
-parsertest "reconcile_new_asp"
-parsertest "reconcile_confed"
-parsertest "reconcile_start_trans"
-parsertest "reconcile_start_trans4"
-parsertest "reconcile_start_trans_error"
-parsertest "redundantset2"
-parsertest "zero-size overflow"
-parsertest "zero-size overflow + valid segment"
-parsertest "invalid segment type"
-
-for {set i 0} {$i < 10} {incr i 1} { onetest "prepend $i" "" "prepend test $i"; }
-for {set i 0} {$i < 5} {incr i 1} { onetest "aggregate $i" "" "aggregate test $i"; }
-for {set i 0} {$i < 5} {incr i 1} { onetest "reconcile $i" "" "reconcile test $i"; }
-for {set i 0} {$i < 22} {incr i 1} { onetest "compare $i" "" "left cmp "; }
-
-onetest "empty_get" "" "empty_get_test"
-attrtest "basic test"
-attrtest "length too short"
-attrtest "length too long"
-attrtest "incorrect flag"
-attrtest "as4_path, with as2 format data"
-attrtest "as4, with incorrect attr length"
-attrtest "basic 4-byte as-path"
-attrtest "4b AS_PATH: too short"
-attrtest "4b AS_PATH: too long"
-attrtest "4b AS_PATH: too long2"
-attrtest "4b AS_PATH: bad flags"
-attrtest "4b AS4_PATH w/o AS_PATH"
-attrtest "4b AS4_PATH: confed"
-
diff --git a/tests/bgpd.tests/ecommtest.exp b/tests/bgpd.tests/ecommtest.exp
deleted file mode 100644
index cbeb03af52..0000000000
--- a/tests/bgpd.tests/ecommtest.exp
+++ /dev/null
@@ -1,13 +0,0 @@
-set timeout 10
-set testprefix "ecommtest "
-set aborted 0
-set color 0
-
-spawn sh -c "exec ./ecommtest 2>/dev/null"
-
-# proc simpletest { start } {
-
-simpletest "ipaddr"
-simpletest "ipaddr-so"
-simpletest "asn"
-simpletest "asn4"
diff --git a/tests/bgpd.tests/testbgpcap.exp b/tests/bgpd.tests/testbgpcap.exp
deleted file mode 100644
index aba6906bc0..0000000000
--- a/tests/bgpd.tests/testbgpcap.exp
+++ /dev/null
@@ -1,51 +0,0 @@
-set timeout 10
-set testprefix "testbgpcap "
-set aborted 0
-set color 1
-
-spawn sh -c "exec ./testbgpcap 2>/dev/null"
-
-# proc simpletest { start } {
-
-simpletest "MP4: MP IP/Uni"
-simpletest "MPv6: MP IPv6/Uni"
-simpletest "MP2: MP IP/Multicast"
-simpletest "MP3: MP IP6/MPLS-labeled VPN"
-simpletest "MP5: MP IP6/MPLS-VPN"
-simpletest "MP6: MP IP4/MPLS-laveled VPN"
-simpletest "MP8: MP unknown AFI/SAFI"
-simpletest "MP-short: MP IP4/Unicast, length too short (< minimum)"
-simpletest "MP-overflow: MP IP4/Unicast, length too long"
-simpletest "caphdr: capability header, and no more"
-simpletest "nodata: header, no data but length says there is"
-simpletest "padded: valid, with padding"
-simpletest "minsize: violates minsize requirement"
-simpletest "ORF: ORF, simple, single entry, single tuple"
-simpletest "ORF-many: ORF, multi entry/tuple"
-simpletest "ORFlo: ORF, multi entry/tuple, hdr length too short"
-simpletest "ORFlu: ORF, multi entry/tuple, length too long"
-simpletest "ORFnu: ORF, multi entry/tuple, entry number too long"
-simpletest "ORFno: ORF, multi entry/tuple, entry number too short"
-simpletest "ORFpad: ORF, multi entry/tuple, padded to align"
-simpletest "AS4: AS4 capability"
-simpletest "GR: GR capability"
-simpletest "GR-short: GR capability, but header length too short"
-simpletest "GR-long: GR capability, but header length too long"
-simpletest "GR-trunc: GR capability, but truncated"
-simpletest "GR-empty: GR capability, but empty."
-simpletest "MP-empty: MP capability, but empty."
-simpletest "ORF-empty: ORF capability, but empty."
-simpletest "AS4-empty: AS4 capability, but empty."
-simpletest "dyn-empty: Dynamic capability, but empty."
-simpletest "dyn-old: Dynamic capability (deprecated version)"
-simpletest "Cap-singlets: One capability per Optional-Param"
-simpletest "Cap-series: Series of capability, one Optional-Param"
-simpletest "AS4more: AS4 capability after other caps (singlets)"
-simpletest "AS4series: AS4 capability, in series of capabilities"
-simpletest "AS4real: AS4 capability, in series of capabilities"
-simpletest "AS4real2: AS4 capability, in series of capabilities"
-simpletest "DynCap: Dynamic Capability Message, IP/Multicast"
-simpletest "DynCapLong: Dynamic Capability Message, IP/Multicast, truncated"
-simpletest "DynCapPadded: Dynamic Capability Message, IP/Multicast, padded"
-simpletest "DynCapMPCpadded: Dynamic Capability Message, IP/Multicast, cap data padded"
-simpletest "DynCapMPCoverflow: Dynamic Capability Message, IP/Multicast, cap data != length"
diff --git a/tests/bgpd.tests/testbgpmpath.exp b/tests/bgpd.tests/testbgpmpath.exp
deleted file mode 100644
index 6820f636a4..0000000000
--- a/tests/bgpd.tests/testbgpmpath.exp
+++ /dev/null
@@ -1,12 +0,0 @@
-set timeout 10
-set testprefix "testbgpmpath "
-set aborted 0
-set color 1
-
-spawn sh -c "exec ./testbgpmpath 2>/dev/null"
-
-# proc simpletest { start } {
-
-simpletest "bgp maximum-paths config"
-simpletest "bgp_mp_list"
-simpletest "bgp_info_mpath_update"
diff --git a/tests/bgpd.tests/testbgpmpattr.exp b/tests/bgpd.tests/testbgpmpattr.exp
deleted file mode 100644
index 1abce3fc9a..0000000000
--- a/tests/bgpd.tests/testbgpmpattr.exp
+++ /dev/null
@@ -1,38 +0,0 @@
-set timeout 10
-set testprefix "testbgpmpattr "
-set aborted 0
-set color 1
-
-spawn sh -c "exec ./testbgpmpattr 2>/dev/null"
-
-# proc simpletest { start } {
-
-simpletest "IPv6: IPV6 MP Reach, global nexthop, 1 NLRI"
-simpletest "IPv6-2: IPV6 MP Reach, global nexthop, 2 NLRIs"
-simpletest "IPv6-default: IPV6 MP Reach, global nexthop, 2 NLRIs + default"
-simpletest "IPv6-lnh: IPV6 MP Reach, global+local nexthops, 2 NLRIs + default"
-simpletest "IPv6-nhlen: IPV6 MP Reach, inappropriate nexthop length"
-simpletest "IPv6-nhlen2: IPV6 MP Reach, invalid nexthop length"
-simpletest "IPv6-nhlen3: IPV6 MP Reach, nexthop length overflow"
-simpletest "IPv6-nhlen4: IPV6 MP Reach, nexthop length short"
-simpletest "IPv6-nlri: IPV6 MP Reach, NLRI bitlen overflow"
-simpletest "IPv4: IPv4 MP Reach, 2 NLRIs + default"
-simpletest "IPv4-nhlen: IPv4 MP Reach, nexthop lenth overflow"
-simpletest "IPv4-nlrilen: IPv4 MP Reach, nlri lenth overflow"
-simpletest "IPv4-VPNv4: IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs"
-simpletest "IPv4-VPNv4-bogus-plen: IPv4/MPLS-labeled VPN MP Reach, RD, Nexthop, NLRI / bogus p'len"
-simpletest "IPv4-VPNv4-plen1-short: IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs, 1st plen short"
-simpletest "IPv4-VPNv4-plen1-long: IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs, 1st plen long"
-simpletest "IPv4-VPNv4-plenn-long: IPv4/VPNv4 MP Reach, RD, Nexthop, 3 NLRIs, last plen long"
-simpletest "IPv4-VPNv4-plenn-short: IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs, last plen short"
-simpletest "IPv4-VPNv4-bogus-rd-type: IPv4/VPNv4 MP Reach, RD, NH, 2 NLRI, unknown RD in 1st (log, but parse)"
-simpletest "IPv4-VPNv4-0-nlri: IPv4/VPNv4 MP Reach, RD, Nexthop, 3 NLRI, 3rd 0 bogus"
-simpletest "IPv6-bug: IPv6, global nexthop, 1 default NLRI"
-simpletest "IPv6-unreach: IPV6 MP Unreach, 1 NLRI"
-simpletest "IPv6-unreach2: IPV6 MP Unreach, 2 NLRIs"
-simpletest "IPv6-unreach-default: IPV6 MP Unreach, 2 NLRIs + default"
-simpletest "IPv6-unreach-nlri: IPV6 MP Unreach, NLRI bitlen overflow"
-simpletest "IPv4-unreach: IPv4 MP Unreach, 2 NLRIs + default"
-simpletest "IPv4-unreach-nlrilen: IPv4 MP Unreach, nlri length overflow"
-simpletest "IPv4-unreach-VPNv4: IPv4/MPLS-labeled VPN MP Unreach, RD, 3 NLRIs"
-
diff --git a/tests/aspath_test.c b/tests/bgpd/test_aspath.c
index f3999cbcff..f3999cbcff 100644
--- a/tests/aspath_test.c
+++ b/tests/bgpd/test_aspath.c
diff --git a/tests/bgpd/test_aspath.py b/tests/bgpd/test_aspath.py
new file mode 100644
index 0000000000..15ae514c87
--- /dev/null
+++ b/tests/bgpd/test_aspath.py
@@ -0,0 +1,79 @@
+import frrtest
+import re
+
+re_okfail = re.compile(r'^(?:\x1b\[3[12]m)?(?P<ret>OK|failed)'.encode('utf8'),
+ re.MULTILINE)
+
+class TestAspath(frrtest.TestMultiOut):
+ program = './test_aspath'
+
+ def _parsertest(self, line):
+ if not hasattr(self, 'parserno'):
+ self.parserno = -1
+ self.parserno += 1
+
+ self._onesimple("test %d" % self.parserno)
+ self._okfail("%s:" % line, okfail=re_okfail)
+ self._okfail("empty prepend %s:" % line, okfail=re_okfail)
+
+ def _attrtest(self, line):
+ if not hasattr(self, 'attrno'):
+ self.attrno = -1
+ self.attrno += 1
+
+ self._onesimple("aspath_attr test %d" % self.attrno)
+ self._okfail(line, okfail=re_okfail)
+
+TestAspath.parsertest("seq1")
+TestAspath.parsertest("seq2")
+TestAspath.parsertest("seq3")
+TestAspath.parsertest("seqset")
+TestAspath.parsertest("seqset2")
+TestAspath.parsertest("multi")
+TestAspath.parsertest("confed")
+TestAspath.parsertest("confed2")
+TestAspath.parsertest("confset")
+TestAspath.parsertest("confmulti")
+TestAspath.parsertest("seq4")
+TestAspath.parsertest("tripleseq1")
+TestAspath.parsertest("someprivate")
+TestAspath.parsertest("allprivate")
+TestAspath.parsertest("long")
+TestAspath.parsertest("seq1extra")
+TestAspath.parsertest("empty")
+TestAspath.parsertest("redundantset")
+TestAspath.parsertest("reconcile_lead_asp")
+TestAspath.parsertest("reconcile_new_asp")
+TestAspath.parsertest("reconcile_confed")
+TestAspath.parsertest("reconcile_start_trans")
+TestAspath.parsertest("reconcile_start_trans4")
+TestAspath.parsertest("reconcile_start_trans_error")
+TestAspath.parsertest("redundantset2")
+TestAspath.parsertest("zero-size overflow")
+TestAspath.parsertest("zero-size overflow + valid segment")
+TestAspath.parsertest("invalid segment type")
+
+for i in range(10):
+ TestAspath.okfail("prepend test %d" % i)
+for i in range(5):
+ TestAspath.okfail("aggregate test %d" % i)
+for i in range(5):
+ TestAspath.okfail("reconcile test %d" % i)
+for _ in range(22):
+ TestAspath.okfail("left cmp ")
+
+TestAspath.okfail("empty_get_test")
+
+TestAspath.attrtest("basic test")
+TestAspath.attrtest("length too short")
+TestAspath.attrtest("length too long")
+TestAspath.attrtest("incorrect flag")
+TestAspath.attrtest("as4_path, with as2 format data")
+TestAspath.attrtest("as4, with incorrect attr length")
+TestAspath.attrtest("basic 4-byte as-path")
+TestAspath.attrtest("4b AS_PATH: too short")
+TestAspath.attrtest("4b AS_PATH: too long")
+TestAspath.attrtest("4b AS_PATH: too long2")
+TestAspath.attrtest("4b AS_PATH: bad flags")
+TestAspath.attrtest("4b AS4_PATH w/o AS_PATH")
+TestAspath.attrtest("4b AS4_PATH: confed")
diff --git a/tests/bgp_capability_test.c b/tests/bgpd/test_capability.c
index f83dee5e1c..f83dee5e1c 100644
--- a/tests/bgp_capability_test.c
+++ b/tests/bgpd/test_capability.c
diff --git a/tests/bgpd/test_capability.py b/tests/bgpd/test_capability.py
new file mode 100644
index 0000000000..4cb650092b
--- /dev/null
+++ b/tests/bgpd/test_capability.py
@@ -0,0 +1,47 @@
+import frrtest
+
+class TestCapability(frrtest.TestMultiOut):
+ program = './test_capability'
+
+TestCapability.okfail("MP4: MP IP/Uni")
+TestCapability.okfail("MPv6: MP IPv6/Uni")
+TestCapability.okfail("MP2: MP IP/Multicast")
+TestCapability.okfail("MP3: MP IP6/MPLS-labeled VPN")
+TestCapability.okfail("MP5: MP IP6/MPLS-VPN")
+TestCapability.okfail("MP6: MP IP4/MPLS-laveled VPN")
+TestCapability.okfail("MP8: MP unknown AFI/SAFI")
+TestCapability.okfail("MP-short: MP IP4/Unicast, length too short (< minimum)")
+TestCapability.okfail("MP-overflow: MP IP4/Unicast, length too long")
+TestCapability.okfail("caphdr: capability header, and no more")
+TestCapability.okfail("nodata: header, no data but length says there is")
+TestCapability.okfail("padded: valid, with padding")
+TestCapability.okfail("minsize: violates minsize requirement")
+TestCapability.okfail("ORF: ORF, simple, single entry, single tuple")
+TestCapability.okfail("ORF-many: ORF, multi entry/tuple")
+TestCapability.okfail("ORFlo: ORF, multi entry/tuple, hdr length too short")
+TestCapability.okfail("ORFlu: ORF, multi entry/tuple, length too long")
+TestCapability.okfail("ORFnu: ORF, multi entry/tuple, entry number too long")
+TestCapability.okfail("ORFno: ORF, multi entry/tuple, entry number too short")
+TestCapability.okfail("ORFpad: ORF, multi entry/tuple, padded to align")
+TestCapability.okfail("AS4: AS4 capability")
+TestCapability.okfail("GR: GR capability")
+TestCapability.okfail("GR-short: GR capability, but header length too short")
+TestCapability.okfail("GR-long: GR capability, but header length too long")
+TestCapability.okfail("GR-trunc: GR capability, but truncated")
+TestCapability.okfail("GR-empty: GR capability, but empty.")
+TestCapability.okfail("MP-empty: MP capability, but empty.")
+TestCapability.okfail("ORF-empty: ORF capability, but empty.")
+TestCapability.okfail("AS4-empty: AS4 capability, but empty.")
+TestCapability.okfail("dyn-empty: Dynamic capability, but empty.")
+TestCapability.okfail("dyn-old: Dynamic capability (deprecated version)")
+TestCapability.okfail("Cap-singlets: One capability per Optional-Param")
+TestCapability.okfail("Cap-series: Series of capability, one Optional-Param")
+TestCapability.okfail("AS4more: AS4 capability after other caps (singlets)")
+TestCapability.okfail("AS4series: AS4 capability, in series of capabilities")
+TestCapability.okfail("AS4real: AS4 capability, in series of capabilities")
+TestCapability.okfail("AS4real2: AS4 capability, in series of capabilities")
+TestCapability.okfail("DynCap: Dynamic Capability Message, IP/Multicast")
+TestCapability.okfail("DynCapLong: Dynamic Capability Message, IP/Multicast, truncated")
+TestCapability.okfail("DynCapPadded: Dynamic Capability Message, IP/Multicast, padded")
+TestCapability.okfail("DynCapMPCpadded: Dynamic Capability Message, IP/Multicast, cap data padded")
+TestCapability.okfail("DynCapMPCoverflow: Dynamic Capability Message, IP/Multicast, cap data != length")
diff --git a/tests/ecommunity_test.c b/tests/bgpd/test_ecommunity.c
index 9166af6142..9166af6142 100644
--- a/tests/ecommunity_test.c
+++ b/tests/bgpd/test_ecommunity.c
diff --git a/tests/bgpd/test_ecommunity.py b/tests/bgpd/test_ecommunity.py
new file mode 100644
index 0000000000..3a17ec9e31
--- /dev/null
+++ b/tests/bgpd/test_ecommunity.py
@@ -0,0 +1,9 @@
+import frrtest
+
+class TestEcommunity(frrtest.TestMultiOut):
+ program = './test_ecommunity'
+
+TestEcommunity.okfail('ipaddr')
+TestEcommunity.okfail('ipaddr-so')
+TestEcommunity.okfail('asn')
+TestEcommunity.okfail('asn4')
diff --git a/tests/bgp_mp_attr_test.c b/tests/bgpd/test_mp_attr.c
index 397612c315..397612c315 100644
--- a/tests/bgp_mp_attr_test.c
+++ b/tests/bgpd/test_mp_attr.c
diff --git a/tests/bgpd/test_mp_attr.py b/tests/bgpd/test_mp_attr.py
new file mode 100644
index 0000000000..46d0c42402
--- /dev/null
+++ b/tests/bgpd/test_mp_attr.py
@@ -0,0 +1,33 @@
+import frrtest
+
+class TestMpAttr(frrtest.TestMultiOut):
+ program = './test_mp_attr'
+
+TestMpAttr.okfail("IPv6: IPV6 MP Reach, global nexthop, 1 NLRI")
+TestMpAttr.okfail("IPv6-2: IPV6 MP Reach, global nexthop, 2 NLRIs")
+TestMpAttr.okfail("IPv6-default: IPV6 MP Reach, global nexthop, 2 NLRIs + default")
+TestMpAttr.okfail("IPv6-lnh: IPV6 MP Reach, global+local nexthops, 2 NLRIs + default")
+TestMpAttr.okfail("IPv6-nhlen: IPV6 MP Reach, inappropriate nexthop length")
+TestMpAttr.okfail("IPv6-nhlen2: IPV6 MP Reach, invalid nexthop length")
+TestMpAttr.okfail("IPv6-nhlen3: IPV6 MP Reach, nexthop length overflow")
+TestMpAttr.okfail("IPv6-nhlen4: IPV6 MP Reach, nexthop length short")
+TestMpAttr.okfail("IPv6-nlri: IPV6 MP Reach, NLRI bitlen overflow")
+TestMpAttr.okfail("IPv4: IPv4 MP Reach, 2 NLRIs + default")
+TestMpAttr.okfail("IPv4-nhlen: IPv4 MP Reach, nexthop lenth overflow")
+TestMpAttr.okfail("IPv4-nlrilen: IPv4 MP Reach, nlri lenth overflow")
+TestMpAttr.okfail("IPv4-VPNv4: IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs")
+TestMpAttr.okfail("IPv4-VPNv4-bogus-plen: IPv4/MPLS-labeled VPN MP Reach, RD, Nexthop, NLRI / bogus p'len")
+TestMpAttr.okfail("IPv4-VPNv4-plen1-short: IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs, 1st plen short")
+TestMpAttr.okfail("IPv4-VPNv4-plen1-long: IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs, 1st plen long")
+TestMpAttr.okfail("IPv4-VPNv4-plenn-long: IPv4/VPNv4 MP Reach, RD, Nexthop, 3 NLRIs, last plen long")
+TestMpAttr.okfail("IPv4-VPNv4-plenn-short: IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs, last plen short")
+TestMpAttr.okfail("IPv4-VPNv4-bogus-rd-type: IPv4/VPNv4 MP Reach, RD, NH, 2 NLRI, unknown RD in 1st (log, but parse)")
+TestMpAttr.okfail("IPv4-VPNv4-0-nlri: IPv4/VPNv4 MP Reach, RD, Nexthop, 3 NLRI, 3rd 0 bogus")
+TestMpAttr.okfail("IPv6-bug: IPv6, global nexthop, 1 default NLRI")
+TestMpAttr.okfail("IPv6-unreach: IPV6 MP Unreach, 1 NLRI")
+TestMpAttr.okfail("IPv6-unreach2: IPV6 MP Unreach, 2 NLRIs")
+TestMpAttr.okfail("IPv6-unreach-default: IPV6 MP Unreach, 2 NLRIs + default")
+TestMpAttr.okfail("IPv6-unreach-nlri: IPV6 MP Unreach, NLRI bitlen overflow")
+TestMpAttr.okfail("IPv4-unreach: IPv4 MP Unreach, 2 NLRIs + default")
+TestMpAttr.okfail("IPv4-unreach-nlrilen: IPv4 MP Unreach, nlri length overflow")
+TestMpAttr.okfail("IPv4-unreach-VPNv4: IPv4/MPLS-labeled VPN MP Unreach, RD, 3 NLRIs")
diff --git a/tests/bgp_mpath_test.c b/tests/bgpd/test_mpath.c
index f9eb1534f3..f9eb1534f3 100644
--- a/tests/bgp_mpath_test.c
+++ b/tests/bgpd/test_mpath.c
diff --git a/tests/bgpd/test_mpath.py b/tests/bgpd/test_mpath.py
new file mode 100644
index 0000000000..3024669507
--- /dev/null
+++ b/tests/bgpd/test_mpath.py
@@ -0,0 +1,9 @@
+import frrtest
+
+class TestMpath(frrtest.TestMultiOut):
+ program = './test_mpath'
+
+TestMpath.okfail("bgp maximum-paths config")
+TestMpath.okfail("bgp_mp_list")
+TestMpath.okfail("bgp_info_mpath_update")
+
diff --git a/tests/config/unix.exp b/tests/config/unix.exp
deleted file mode 100644
index 2f6bceadbe..0000000000
--- a/tests/config/unix.exp
+++ /dev/null
@@ -1,102 +0,0 @@
-
-# every test should always be run and always return some status.
-# so, if we lose sync with a multi-test program, aborted will be used
-# to flag the remainder of the tests as untested.
-#set aborted 0
-
-# only match with color codes since "failed" / "OK" might otherwise
-# be part of the output...
-#set color 1
-
-set xfail 0
-
-proc onesimple { test_name match } {
- global verbose
- global aborted
- global testprefix
- if { $aborted > 0 } {
- untested "$testprefix$test_name"
- return
- }
- if { $verbose > 0 } {
- send_user "$testprefix$test_name$note\n"
- }
- expect {
- "$match" { pass "$testprefix$test_name"; }
- eof { fail "$testprefix$test_name"; set aborted 1; }
- timeout { unresolved "$testprefix$test_name"; set aborted 1; }
- }
-}
-
-proc onetest { test_name note start } {
- global aborted
- global testprefix
- global verbose
- global color
- global xfail
-
- if { $aborted > 0 } {
- untested "$testprefix$test_name"
- return
- }
-
- if { $verbose > 0 } {
- send_user "$testprefix$test_name$note\n"
- }
- expect {
- "$start" { }
-
- eof { unresolved "$testprefix$test_name"; set aborted 1; }
- timeout { unresolved "$testprefix$test_name"; set aborted 1; }
- }
-
- if { $aborted > 0 } {
- send_user "sync failed: $testprefix$test_name$note -- $testprefix aborted!\n"
- return
- }
-
- if { $color } {
- set pat "(32mOK|31mfailed)"
- } else {
- set pat "(OK|failed)"
- }
- expect {
- # need this because otherwise expect will skip over a "failed" and
- # grab the next "OK" (or the other way around)
- -re "$pat" {
- if { "$expect_out(0,string)" == "32mOK" || "$expect_out(0,string)" == "OK" } {
- pass "$testprefix$test_name"
- } else {
- if { $xfail } {
- xfail "$testprefix$test_name"
- } else {
- fail "$testprefix$test_name"
- }
- }
- return
- }
-
- eof { unresolved "$testprefix$test_name"; set aborted 1; }
- timeout { unresolved "$testprefix$test_name"; set aborted 1; }
- }
-
- if { $aborted > 0 } {
- send_user "failed: $testprefix$test_name$note -- $testprefix aborted!\n"
- return
- }
-}
-
-proc headerline { line } {
- global aborted
- if { $aborted > 0 } { return; }
- expect {
- $line { return; }
- eof { send_user "numbering mismatch!\n"; set aborted 1; }
- timeout { send_user "numbering mismatch!\n"; set aborted 1; }
- }
-}
-
-proc simpletest { start } {
- onetest "$start" "" "$start"
-}
-
diff --git a/tests/global-conf.exp b/tests/global-conf.exp
deleted file mode 100644
index e69de29bb2..0000000000
--- a/tests/global-conf.exp
+++ /dev/null
diff --git a/tests/main.c b/tests/helpers/c/main.c
index b3e6e706ff..b3e6e706ff 100644
--- a/tests/main.c
+++ b/tests/helpers/c/main.c
diff --git a/tests/prng.c b/tests/helpers/c/prng.c
index bdcfb07af1..bdcfb07af1 100644
--- a/tests/prng.c
+++ b/tests/helpers/c/prng.c
diff --git a/tests/prng.h b/tests/helpers/c/prng.h
index cf0bacc5f8..cf0bacc5f8 100644
--- a/tests/prng.h
+++ b/tests/helpers/c/prng.h
diff --git a/tests/tests.h b/tests/helpers/c/tests.h
index a528e55f05..a528e55f05 100644
--- a/tests/tests.h
+++ b/tests/helpers/c/tests.h
diff --git a/tests/helpers/python/frrsix.py b/tests/helpers/python/frrsix.py
new file mode 100644
index 0000000000..91714f0c67
--- /dev/null
+++ b/tests/helpers/python/frrsix.py
@@ -0,0 +1,80 @@
+#
+# Copyright (c) 2010-2017 Benjamin Peterson
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+
+#
+# This code is taken from the six python2 to python3 compatibility module
+#
+
+import sys
+
+PY2 = sys.version_info[0] == 2
+PY3 = sys.version_info[0] == 3
+
+def add_metaclass(metaclass):
+ """Class decorator for creating a class with a metaclass."""
+ def wrapper(cls):
+ orig_vars = cls.__dict__.copy()
+ slots = orig_vars.get('__slots__')
+ if slots is not None:
+ if isinstance(slots, str):
+ slots = [slots]
+ for slots_var in slots:
+ orig_vars.pop(slots_var)
+ orig_vars.pop('__dict__', None)
+ orig_vars.pop('__weakref__', None)
+ return metaclass(cls.__name__, cls.__bases__, orig_vars)
+ return wrapper
+
+if PY3:
+ import builtins
+ exec_ = getattr(builtins,'exec')
+
+ def reraise(tp, value, tb=None):
+ try:
+ if value is None:
+ value = tp()
+ if value.__traceback__ is not tb:
+ raise value.with_traceback(tb)
+ raise value
+ finally:
+ value = None
+ tb = None
+
+else:
+ def exec_(_code_, _globs_=None, _locs_=None):
+ """Execute code in a namespace."""
+ if _globs_ is None:
+ frame = sys._getframe(1)
+ _globs_ = frame.f_globals
+ if _locs_ is None:
+ _locs_ = frame.f_locals
+ del frame
+ elif _locs_ is None:
+ _locs_ = _globs_
+ exec("""exec _code_ in _globs_, _locs_""")
+
+ exec_("""def reraise(tp, value, tb=None):
+ try:
+ raise tp, value, tb
+ finally:
+ tb = None
+""")
diff --git a/tests/helpers/python/frrtest.py b/tests/helpers/python/frrtest.py
new file mode 100644
index 0000000000..2814416d11
--- /dev/null
+++ b/tests/helpers/python/frrtest.py
@@ -0,0 +1,177 @@
+#
+# Test helpers for FRR
+#
+# Copyright (C) 2017 by David Lamparter & Christian Franke,
+# Open Source Routing / NetDEF Inc.
+#
+# This file is part of FreeRangeRouting (FRR)
+#
+# FRR is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+#
+# FRR is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with FRR; see the file COPYING. If not, write to the Free
+# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+
+import subprocess
+import sys
+import re
+import inspect
+import os
+
+import frrsix
+
+#
+# These are the gritty internals of the TestMultiOut implementation.
+# See below for the definition of actual TestMultiOut tests.
+#
+
+class MultiTestFailure(Exception):
+ pass
+
+class MetaTestMultiOut(type):
+ def __getattr__(cls, name):
+ if name.startswith('_'):
+ raise AttributeError
+
+ internal_name = '_{}'.format(name)
+ if internal_name not in dir(cls):
+ raise AttributeError
+
+ def registrar(*args, **kwargs):
+ cls._add_test(getattr(cls,internal_name), *args, **kwargs)
+ return registrar
+
+@frrsix.add_metaclass(MetaTestMultiOut)
+class _TestMultiOut(object):
+ def _run_tests(self):
+ if 'tests_run' in dir(self.__class__) and self.tests_run:
+ return
+ self.__class__.tests_run = True
+ basedir = os.path.dirname(inspect.getsourcefile(type(self)))
+ program = os.path.join(basedir, self.program)
+ proc = subprocess.Popen([program], stdout=subprocess.PIPE)
+ self.output,_ = proc.communicate('')
+ self.exitcode = proc.wait()
+
+ self.__class__.testresults = {}
+ for test in self.tests:
+ try:
+ test(self)
+ except MultiTestFailure:
+ self.testresults[test] = sys.exc_info()
+ else:
+ self.testresults[test] = None
+
+ def _exit_cleanly(self):
+ if self.exitcode != 0:
+ raise MultiTestFailure("Program did not terminate with exit code 0")
+
+ @classmethod
+ def _add_test(cls, method, *args, **kwargs):
+ if 'tests' not in dir(cls):
+ setattr(cls,'tests',[])
+ cls._add_test(cls._exit_cleanly)
+
+ def matchfunction(self):
+ method(self, *args, **kwargs)
+ cls.tests.append(matchfunction)
+
+ def testfunction(self):
+ self._run_tests()
+ result = self.testresults[matchfunction]
+ if result is not None:
+ frrsix.reraise(*result)
+
+ testname = re.sub(r'[^A-Za-z0-9]', '_', '%r%r' % (args, kwargs))
+ testname = re.sub(r'__*', '_', testname)
+ testname = testname.strip('_')
+ if not testname:
+ testname = method.__name__.strip('_')
+ if "test_%s" % testname in dir(cls):
+ index = 2
+ while "test_%s_%d" % (testname,index) in dir(cls):
+ index += 1
+ testname = "%s_%d" % (testname, index)
+ setattr(cls,"test_%s" % testname, testfunction)
+
+#
+# This class houses the actual TestMultiOut tests types.
+# If you want to add a new test type, you probably do it here.
+#
+# Say you want to add a test type called foobarlicious. Then define
+# a function _foobarlicious here that takes self and the test arguments
+# when called. That function should check the output in self.output
+# to see whether it matches the expectation of foobarlicious with the
+# given arguments and should then adjust self.output according to how
+# much output it consumed.
+# If the output doesn't meet the expectations, MultiTestFailure can be
+# raised, however that should only be done after self.output has been
+# modified according to consumed content.
+#
+
+re_okfail = re.compile(r'(?:[3[12]m|^)?(?P<ret>OK|failed)'.encode('utf8'),
+ re.MULTILINE)
+class TestMultiOut(_TestMultiOut):
+ def _onesimple(self, line):
+ if type(line) is str:
+ line = line.encode('utf8')
+ idx = self.output.find(line)
+ if idx != -1:
+ self.output = self.output[idx+len(line):]
+ else:
+ raise MultiTestFailure("%r could not be found" % line)
+
+ def _okfail(self, line, okfail=re_okfail):
+ self._onesimple(line)
+
+ m = okfail.search(self.output)
+ if m is None:
+ raise MultiTestFailure('OK/fail not found')
+ self.output = self.output[m.end():]
+
+ if m.group('ret') != 'OK'.encode('utf8'):
+ raise MultiTestFailure('Test output indicates failure')
+
+#
+# This class implements a test comparing the output of a program against
+# an existing reference output
+#
+
+class TestRefMismatch(Exception):
+ pass
+class TestExitNonzero(Exception):
+ pass
+
+class TestRefOut(object):
+ def test_refout(self):
+ basedir = os.path.dirname(inspect.getsourcefile(type(self)))
+ program = os.path.join(basedir, self.program)
+
+ refin = program + '.in'
+ refout = program + '.refout'
+
+ intext = ''
+ if os.path.exists(refin):
+ with open(refin, 'rb') as f:
+ intext = f.read()
+ with open(refout, 'rb') as f:
+ reftext = f.read()
+
+ proc = subprocess.Popen([program],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ outtext,_ = proc.communicate(intext)
+ if outtext != reftext:
+ raise TestRefMismatch(self, outtext, reftext)
+ if proc.wait() != 0:
+ raise TestExitNonzero(self)
diff --git a/tests/lib/bgpd.exp b/tests/lib/bgpd.exp
deleted file mode 100644
index e69de29bb2..0000000000
--- a/tests/lib/bgpd.exp
+++ /dev/null
diff --git a/tests/common-cli.c b/tests/lib/cli/common_cli.c
index 47476711c6..83196e04aa 100644
--- a/tests/common-cli.c
+++ b/tests/lib/cli/common_cli.c
@@ -29,7 +29,7 @@
#include "memory_vty.h"
#include "log.h"
-#include "common-cli.h"
+#include "common_cli.h"
struct thread_master *master;
diff --git a/tests/common-cli.h b/tests/lib/cli/common_cli.h
index 9c72b08e44..9c72b08e44 100644
--- a/tests/common-cli.h
+++ b/tests/lib/cli/common_cli.h
diff --git a/tests/test-cli.c b/tests/lib/cli/test_cli.c
index 0590eec713..1a316022e2 100644
--- a/tests/test-cli.c
+++ b/tests/lib/cli/test_cli.c
@@ -22,7 +22,7 @@
#include <zebra.h>
-#include "common-cli.h"
+#include "common_cli.h"
DUMMY_DEFUN(cmd0, "arg ipv4 A.B.C.D");
DUMMY_DEFUN(cmd1, "arg ipv4m A.B.C.D/M");
diff --git a/tests/testcli.in b/tests/lib/cli/test_cli.in
index 5c146ef984..5c146ef984 100644
--- a/tests/testcli.in
+++ b/tests/lib/cli/test_cli.in
diff --git a/tests/lib/cli/test_cli.py b/tests/lib/cli/test_cli.py
new file mode 100644
index 0000000000..e3c31c2d91
--- /dev/null
+++ b/tests/lib/cli/test_cli.py
@@ -0,0 +1,4 @@
+import frrtest
+
+class TestCli(frrtest.TestRefOut):
+ program = './test_cli'
diff --git a/tests/testcli.refout b/tests/lib/cli/test_cli.refout
index 8b438baee2..8b438baee2 100644
--- a/tests/testcli.refout
+++ b/tests/lib/cli/test_cli.refout
diff --git a/tests/test-commands.c b/tests/lib/cli/test_commands.c
index 272e3d12b7..272e3d12b7 100644
--- a/tests/test-commands.c
+++ b/tests/lib/cli/test_commands.c
diff --git a/tests/testcommands.in b/tests/lib/cli/test_commands.in
index 7fe62799f1..7fe62799f1 100644
--- a/tests/testcommands.in
+++ b/tests/lib/cli/test_commands.in
diff --git a/tests/lib/cli/test_commands.py b/tests/lib/cli/test_commands.py
new file mode 100644
index 0000000000..85e34fa15b
--- /dev/null
+++ b/tests/lib/cli/test_commands.py
@@ -0,0 +1,8 @@
+import frrtest
+import pytest
+import os
+
+@pytest.mark.skipif('QUAGGA_TEST_COMMANDS' not in os.environ,
+ reason='QUAGGA_TEST_COMMANDS not set')
+class TestCommands(frrtest.TestRefOut):
+ program = './test_commands'
diff --git a/tests/testcommands.refout b/tests/lib/cli/test_commands.refout
index 9d4a6ef03e..9d4a6ef03e 100644
--- a/tests/testcommands.refout
+++ b/tests/lib/cli/test_commands.refout
diff --git a/tests/lib/libfrr.exp b/tests/lib/libfrr.exp
deleted file mode 100644
index e69de29bb2..0000000000
--- a/tests/lib/libfrr.exp
+++ /dev/null
diff --git a/tests/test-buffer.c b/tests/lib/test_buffer.c
index 67e4035806..67e4035806 100644
--- a/tests/test-buffer.c
+++ b/tests/lib/test_buffer.c
diff --git a/tests/test-checksum.c b/tests/lib/test_checksum.c
index 53ab260e26..53ab260e26 100644
--- a/tests/test-checksum.c
+++ b/tests/lib/test_checksum.c
diff --git a/tests/heavy.c b/tests/lib/test_heavy.c
index 6ba8d9aa6d..6ba8d9aa6d 100644
--- a/tests/heavy.c
+++ b/tests/lib/test_heavy.c
diff --git a/tests/heavy-thread.c b/tests/lib/test_heavy_thread.c
index c43fa76c0e..c43fa76c0e 100644
--- a/tests/heavy-thread.c
+++ b/tests/lib/test_heavy_thread.c
diff --git a/tests/heavy-wq.c b/tests/lib/test_heavy_wq.c
index 97371face1..97371face1 100644
--- a/tests/heavy-wq.c
+++ b/tests/lib/test_heavy_wq.c
diff --git a/tests/test-memory.c b/tests/lib/test_memory.c
index 6849b9dceb..6849b9dceb 100644
--- a/tests/test-memory.c
+++ b/tests/lib/test_memory.c
diff --git a/tests/test-nexthop-iter.c b/tests/lib/test_nexthop_iter.c
index 250379329b..250379329b 100644
--- a/tests/test-nexthop-iter.c
+++ b/tests/lib/test_nexthop_iter.c
diff --git a/tests/lib/test_nexthop_iter.py b/tests/lib/test_nexthop_iter.py
new file mode 100644
index 0000000000..bb330a1c75
--- /dev/null
+++ b/tests/lib/test_nexthop_iter.py
@@ -0,0 +1,7 @@
+import frrtest
+
+class TestNexthopIter(frrtest.TestMultiOut):
+ program = './test_nexthop_iter'
+
+TestNexthopIter.onesimple('Simple test passed.')
+TestNexthopIter.onesimple('PRNG test passed.')
diff --git a/tests/test-privs.c b/tests/lib/test_privs.c
index c6ccc28e7a..c6ccc28e7a 100644
--- a/tests/test-privs.c
+++ b/tests/lib/test_privs.c
diff --git a/tests/test-segv.c b/tests/lib/test_segv.c
index 1810c5f4b2..1810c5f4b2 100644
--- a/tests/test-segv.c
+++ b/tests/lib/test_segv.c
diff --git a/tests/test-sig.c b/tests/lib/test_sig.c
index 4a04240303..4a04240303 100644
--- a/tests/test-sig.c
+++ b/tests/lib/test_sig.c
diff --git a/tests/test-srcdest-table.c b/tests/lib/test_srcdest_table.c
index cfc2deb8d6..cfc2deb8d6 100644
--- a/tests/test-srcdest-table.c
+++ b/tests/lib/test_srcdest_table.c
diff --git a/tests/lib/test_srcdest_table.py b/tests/lib/test_srcdest_table.py
new file mode 100644
index 0000000000..ee73121025
--- /dev/null
+++ b/tests/lib/test_srcdest_table.py
@@ -0,0 +1,6 @@
+import frrtest
+
+class TestSrcdestTable(frrtest.TestMultiOut):
+ program = './test_srcdest_table'
+
+TestSrcdestTable.onesimple('PRNG Test successful.')
diff --git a/tests/test-stream.c b/tests/lib/test_stream.c
index 3ac45eb203..3ac45eb203 100644
--- a/tests/test-stream.c
+++ b/tests/lib/test_stream.c
diff --git a/tests/lib/test_stream.py b/tests/lib/test_stream.py
new file mode 100644
index 0000000000..6f42db1839
--- /dev/null
+++ b/tests/lib/test_stream.py
@@ -0,0 +1,4 @@
+import frrtest
+
+class TestStream(frrtest.TestRefOut):
+ program = './test_stream'
diff --git a/tests/lib/test_stream.refout b/tests/lib/test_stream.refout
new file mode 100644
index 0000000000..cf52e1301e
--- /dev/null
+++ b/tests/lib/test_stream.refout
@@ -0,0 +1,8 @@
+endp: 15, readable: 15, writeable: 1009
+0xef 0xbe 0xef 0xde 0xad 0xbe 0xef 0xde 0xad 0xbe 0xef 0xde 0xad 0xbe 0xef
+endp: 15, readable: 15, writeable: 0
+0xef 0xbe 0xef 0xde 0xad 0xbe 0xef 0xde 0xad 0xbe 0xef 0xde 0xad 0xbe 0xef
+c: 0xef
+w: 0xbeef
+l: 0xdeadbeef
+q: 0xdeadbeefdeadbeef
diff --git a/tests/table_test.c b/tests/lib/test_table.c
index 4042e1aaa2..4042e1aaa2 100644
--- a/tests/table_test.c
+++ b/tests/lib/test_table.c
diff --git a/tests/lib/test_table.py b/tests/lib/test_table.py
new file mode 100644
index 0000000000..e724421273
--- /dev/null
+++ b/tests/lib/test_table.py
@@ -0,0 +1,10 @@
+import frrtest
+
+class TestTable(frrtest.TestMultiOut):
+ program = './test_table'
+
+for i in range(6):
+ TestTable.onesimple('Verifying cmp')
+for i in range(11):
+ TestTable.onesimple('Verifying successor')
+TestTable.onesimple('Verified pausing')
diff --git a/tests/test-timer-correctness.c b/tests/lib/test_timer_correctness.c
index e523929be1..e523929be1 100644
--- a/tests/test-timer-correctness.c
+++ b/tests/lib/test_timer_correctness.c
diff --git a/tests/lib/test_timer_correctness.py b/tests/lib/test_timer_correctness.py
new file mode 100644
index 0000000000..8b4a765a81
--- /dev/null
+++ b/tests/lib/test_timer_correctness.py
@@ -0,0 +1,6 @@
+import frrtest
+
+class TestTimerCorrectness(frrtest.TestMultiOut):
+ program = './test_timer_correctness'
+
+TestTimerCorrectness.onesimple('Expected output and actual output match.')
diff --git a/tests/test-timer-performance.c b/tests/lib/test_timer_performance.c
index a7d09beecc..a7d09beecc 100644
--- a/tests/test-timer-performance.c
+++ b/tests/lib/test_timer_performance.c
diff --git a/tests/libfrr.tests/Makefile.am b/tests/libfrr.tests/Makefile.am
deleted file mode 100644
index 4b74e2d3fb..0000000000
--- a/tests/libfrr.tests/Makefile.am
+++ /dev/null
@@ -1,6 +0,0 @@
-EXTRA_DIST = \
- tabletest.exp \
- test-timer-correctness.exp \
- testcommands.exp \
- testcli.exp \
- testnexthopiter.exp
diff --git a/tests/libfrr.tests/tabletest.exp b/tests/libfrr.tests/tabletest.exp
deleted file mode 100644
index 7496994b7f..0000000000
--- a/tests/libfrr.tests/tabletest.exp
+++ /dev/null
@@ -1,9 +0,0 @@
-set timeout 10
-set testprefix "tabletest "
-set aborted 0
-
-spawn sh -c "exec ./tabletest 2>/dev/null"
-
-for {set i 0} {$i < 6} {incr i 1} { onesimple "cmp $i" "Verifying cmp"; }
-for {set i 0} {$i < 11} {incr i 1} { onesimple "succ $i" "Verifying successor"; }
-onesimple "pause" "Verified pausing"
diff --git a/tests/libfrr.tests/test-timer-correctness.exp b/tests/libfrr.tests/test-timer-correctness.exp
deleted file mode 100644
index 570150cd51..0000000000
--- a/tests/libfrr.tests/test-timer-correctness.exp
+++ /dev/null
@@ -1,7 +0,0 @@
-set timeout 10
-set testprefix "test-timer-correctness"
-set aborted 0
-
-spawn sh -c "exec ./test-timer-correctness 2>/dev/null"
-
-onesimple "" "Expected output and actual output match."
diff --git a/tests/libfrr.tests/testcli.exp b/tests/libfrr.tests/testcli.exp
deleted file mode 100644
index 778bd0caa3..0000000000
--- a/tests/libfrr.tests/testcli.exp
+++ /dev/null
@@ -1,23 +0,0 @@
-set timeout 30
-set test_name "testcli"
-
-spawn sh -c "./testcli < $env(srcdir)/testcli.in | diff -au $env(srcdir)/testcli.refout -"
-
-expect {
- eof {
- }
- timeout {
- exp_close
- fail "$test_name: timeout"
- }
-}
-
-catch wait result
-set os_error [lindex $result 2]
-set exit_status [lindex $result 3]
-
-if { $os_error == 0 && $exit_status == 0 } {
- pass "$test_name"
-} else {
- fail "$test_name"
-}
diff --git a/tests/libfrr.tests/testcommands.exp b/tests/libfrr.tests/testcommands.exp
deleted file mode 100644
index c5d5a00730..0000000000
--- a/tests/libfrr.tests/testcommands.exp
+++ /dev/null
@@ -1,31 +0,0 @@
-set timeout 30
-set test_name "testcommands"
-
-if {![info exists env(QUAGGA_TEST_COMMANDS)]} {
- # sadly, the test randomly fails when configure parameters differ from
- # what was used to create testcommands.refout. this can be fixed by
- # shipping a matching vtysh_cmd.c, which we'll add after 0.99.23
- pass "$test_name"
- return 0
-}
-
-spawn sh -c "./testcommands -e 0 < $env(srcdir)/testcommands.in | diff -au - $env(srcdir)/testcommands.refout"
-
-expect {
- eof {
- }
- timeout {
- exp_close
- fail "$test_name: timeout"
- }
-}
-
-catch wait result
-set os_error [lindex $result 2]
-set exit_status [lindex $result 3]
-
-if { $os_error == 0 && $exit_status == 0 } {
- pass "$test_name"
-} else {
- fail "$test_name"
-}
diff --git a/tests/libfrr.tests/testnexthopiter.exp b/tests/libfrr.tests/testnexthopiter.exp
deleted file mode 100644
index 777b753995..0000000000
--- a/tests/libfrr.tests/testnexthopiter.exp
+++ /dev/null
@@ -1,8 +0,0 @@
-set timeout 10
-set testprefix "testnexthopiter "
-set aborted 0
-
-spawn sh -c "exec ./testnexthopiter 2>/dev/null"
-
-onesimple "simple" "Simple test passed."
-onesimple "prng" "PRNG test passed."
diff --git a/tests/libfrr.tests/teststream.exp b/tests/libfrr.tests/teststream.exp
deleted file mode 100644
index c977bb4417..0000000000
--- a/tests/libfrr.tests/teststream.exp
+++ /dev/null
@@ -1,28 +0,0 @@
-set timeout 10
-spawn sh -c "exec ./teststream 2>/dev/null"
-
-expect {
- "endp: 15, readable: 15, writeable: 1009" { }
- eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } }
-expect {
- "0xef 0xbe 0xef 0xde 0xad 0xbe 0xef 0xde 0xad 0xbe 0xef 0xde 0xad 0xbe 0xef" { }
- eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } }
-expect {
- "endp: 15, readable: 15, writeable: 0" { }
- eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } }
-expect {
- "0xef 0xbe 0xef 0xde 0xad 0xbe 0xef 0xde 0xad 0xbe 0xef 0xde 0xad 0xbe 0xef" { }
- eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } }
-expect {
- "c: 0xef" { }
- eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } }
-expect {
- "w: 0xbeef" { }
- eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } }
-expect {
- "l: 0xdeadbeef" { }
- eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } }
-expect {
- "q: 0xdeadbeefdeadbeef" { }
- eof { fail "teststream"; exit; } timeout { fail "teststream"; exit; } }
-pass "teststream"
diff --git a/tests/libzebra.tests/test-srcdest-table.exp b/tests/libzebra.tests/test-srcdest-table.exp
deleted file mode 100644
index 069d15d39e..0000000000
--- a/tests/libzebra.tests/test-srcdest-table.exp
+++ /dev/null
@@ -1,7 +0,0 @@
-set timeout 10
-set testprefix "test-srcdest-table "
-set aborted 0
-
-spawn "./test-srcdest-table"
-
-onesimple "prng" "PRNG Test successful."
diff --git a/tests/runtests.py b/tests/runtests.py
new file mode 100644
index 0000000000..533dc6b167
--- /dev/null
+++ b/tests/runtests.py
@@ -0,0 +1,6 @@
+import pytest
+import sys
+import os
+
+sys.path.append(os.path.join(os.path.dirname(__file__), 'helpers','python'))
+raise SystemExit(pytest.main(sys.argv[1:]))