+ifdef VPP_ZOMBIE_NOCHECK
+VPP_PIDS=
+else
+VPP_PIDS=$(shell pgrep -d, -x vpp_main)
+endif
+
+ifeq ($(DEBUG),gdb)
+FORCE_FOREGROUND=1
+else ifeq ($(DEBUG),gdbserver)
+FORCE_FOREGROUND=1
+else ifeq ($(DEBUG),gdb-all)
+FORCE_FOREGROUND=1
+else ifeq ($(DEBUG),gdbserver-all)
+FORCE_FOREGROUND=1
+else ifeq ($(DEBUG),core)
+FORCE_FOREGROUND=1
+else ifeq ($(STEP),yes)
+FORCE_FOREGROUND=1
+else ifeq ($(STEP),y)
+FORCE_FOREGROUND=1
+else ifeq ($(STEP),1)
+FORCE_FOREGROUND=1
+else
+FORCE_FOREGROUND=0
+endif
+
+ifdef PROFILE_OUTPUT
+PROFILE_OUTPUT_OPTS=-o $(PROFILE_OUTPUT)
+endif
+
+ifndef PROFILE_SORT_BY
+PROFILE_SORT_BY=cumtime
+endif
+
+ifeq ($(PROFILE),1)
+PYTHON_PROFILE_OPTS=-m cProfile $(PROFILE_OUTPUT_OPTS) -s $(PROFILE_SORT_BY)
+FORCE_FOREGROUND=1
+endif
+
+verify-no-running-vpp:
+ @if [ "$(VPP_PIDS)" != "" ]; then \
+ echo; \
+ echo "*** Existing vpp processes detected (PID(s): $(VPP_PIDS)). Running tests under these conditions is not supported. ***"; \
+ echo; \
+ ps -fp $(VPP_PIDS);\
+ echo; \
+ false; \
+ fi
+
+UNITTEST_EXTRA_OPTS=
+UNITTEST_FAILFAST_OPTS=
+
+ifeq ($(FAILFAST),1)
+UNITTEST_EXTRA_OPTS=-f
+endif
+
+ifneq ($(EXTERN_TESTS),)
+UNITTEST_EXTRA_OPTS=$(UNITTEST_FAILFAST_OPTS) -d $(EXTERN_TESTS)
+endif
+
+VENV_PATH=$(TEST_BR)/venv
+
+ifeq ($(TEST_DEBUG),1)
+VENV_RUN_DIR:=$(VENV_PATH)/run-debug
+else
+VENV_RUN_DIR:=$(VENV_PATH)/run
+endif
+
+ifeq ($(PYTHON),)
+PYTHON_INTERP=python3
+else
+PYTHON_INTERP=$(PYTHON)
+endif
+
+PYTHON_VERSION=$(shell $(PYTHON_INTERP) -c 'import sys; print(sys.version_info.major)')
+PIP_VERSION=19.1.1
+PIP_TOOLS_VERSION=3.8.0 # Keep in sync with requirements.txt
+PYTHON_DEPENDS=requirements-$(PYTHON_VERSION).txt
+SCAPY_SOURCE=$(shell find $(VENV_PATH)/lib/python* -name site-packages)
+BUILD_COV_DIR=$(TEST_BR)/coverage
+
+PIP_TOOLS_INSTALL_DONE=$(VENV_RUN_DIR)/pip-tools-install-$(PYTHON_VERSION).done
+PIP_INSTALL_DONE=$(VENV_RUN_DIR)/pip-install-$(PYTHON_VERSION).done
+PIP_PATCH_DONE=$(VENV_RUN_DIR)/pip-patch-$(PYTHON_VERSION).done
+PAPI_INSTALL_DONE=$(VENV_RUN_DIR)/papi-install-$(PYTHON_VERSION).done
+PAPI_PYTHON_SRC_DIR=$(WS_ROOT)/src/vpp-api/python
+PAPI_WIPE_DIST=$(WS_ROOT)/src/vpp-api/vapi/__pycache__ \
+ $(PAPI_PYTHON_SRC_DIR)/build \
+ $(PAPI_PYTHON_SRC_DIR)/vpp_papi.egg-info \
+ $(PAPI_PYTHON_SRC_DIR)/vpp_papi/__pycache__
+
+PAPI_INSTALL_FLAGS=$(PIP_INSTALL_DONE) $(PIP_PATCH_DONE) $(PAPI_INSTALL_DONE)
+
+$(PIP_TOOLS_INSTALL_DONE):
+ @rm -rf $(VENV_PATH)
+ @mkdir -p $(VENV_RUN_DIR)
+ @virtualenv $(VENV_PATH) -p $(PYTHON_INTERP)
+ # pip version pinning
+ @bash -c "source $(VENV_PATH)/bin/activate && \
+ $(PYTHON_INTERP) -m pip install pip===$(PIP_VERSION)"
+ @bash -c "source $(VENV_PATH)/bin/activate && \
+ $(PYTHON_INTERP) -m pip install pip-tools===$(PIP_TOOLS_VERSION)"
+ @touch $@
+
+$(PYTHON_DEPENDS): $(PIP_TOOLS_INSTALL_DONE) requirements.txt
+ @bash -c "source $(VENV_PATH)/bin/activate && \
+ CUSTOM_COMPILE_COMMAND='make test-refresh-deps (or update requirements.txt)' \
+ $(PYTHON_INTERP) -m piptools compile -q --generate-hashes requirements.txt --output-file $@"
+
+$(PIP_INSTALL_DONE): $(PYTHON_DEPENDS)
+ @bash -c "source $(VENV_PATH)/bin/activate && \
+ $(PYTHON_INTERP) -m piptools sync $(PYTHON_DEPENDS)"
+ @touch $@
+
+$(PIP_PATCH_DONE): $(PIP_INSTALL_DONE)
+ @echo --- patching ---
+ @sleep 1 # Ensure python recompiles patched *.py files -> *.pyc
+ for f in $(CURDIR)/patches/scapy-2.4.3/*.patch ; do \
+ echo Applying patch: $$(basename $$f) ; \
+ patch --forward -p1 -d $(SCAPY_SOURCE) < $$f ; \
+ retCode=$$?; \
+ [ $$retCode -gt 0 ] && exit $$retCode; \
+ done; \
+ touch $@
+
+$(PAPI_INSTALL_DONE): $(PIP_PATCH_DONE)
+ @bash -c "source $(VENV_PATH)/bin/activate && $(PYTHON_INTERP) -m pip install -e $(PAPI_PYTHON_SRC_DIR)"
+ @touch $@
+
+.PHONY: refresh-deps
+refresh-deps: clean-deps $(PYTHON_DEPENDS)
+
+.PHONY: clean-deps
+clean-deps:
+ @rm -f $(PYTHON_DEPENDS)
+
+INTERN_PLUGIN_SRC_DIR=$(WS_ROOT)/src/plugins
+ifneq ($(EXTERN_PLUGIN_SRC_DIR),)
+PLUGIN_SRC_DIR=$(EXTERN_PLUGIN_SRC_DIR)
+else
+PLUGIN_SRC_DIR=$(INTERN_PLUGIN_SRC_DIR)
+endif
+
+define retest-func
+@env FORCE_FOREGROUND=$(FORCE_FOREGROUND) FAILED_DIR=$(FAILED_DIR) VENV_PATH=$(VENV_PATH) scripts/setsid_wrapper.sh $(FORCE_FOREGROUND) $(VENV_PATH)/bin/activate $(PYTHON_INTERP) $(PYTHON_PROFILE_OPTS) $(BUILD_TEST_SRC)/run_tests.py -d $(BUILD_TEST_SRC) $(UNITTEST_EXTRA_OPTS) || env FAILED_DIR=$(FAILED_DIR) COMPRESS_FAILED_TEST_LOGS=$(COMPRESS_FAILED_TEST_LOGS) scripts/compress_failed.sh
+endef
+
+.PHONY: sanity
+
+ifeq ($(SANITY),no)
+SANITY_IMPORT_VPP_PAPI_CMD=true
+SANITY_RUN_VPP_CMD=true
+else
+SANITY_IMPORT_VPP_PAPI_CMD=source $(VENV_PATH)/bin/activate && $(PYTHON_INTERP) $(BUILD_TEST_SRC)/sanity_import_vpp_papi.py
+SANITY_RUN_VPP_CMD=source $(VENV_PATH)/bin/activate && PYTHONPATH=$(BUILD_TEST_SRC) $(PYTHON_INTERP) $(BUILD_TEST_SRC)/sanity_run_vpp.py
+endif
+
+ifndef TEST_JOBS
+PARALLEL_ILLEGAL=0
+else ifeq ($(FORCE_FOREGROUND),0)
+PARALLEL_ILLEGAL=0
+else ifeq ($(TEST_JOBS),auto)
+PARALLEL_ILLEGAL=0
+else ifeq ($(TEST_JOBS),1)
+PARALLEL_ILLEGAL=0
+else
+PARALLEL_ILLEGAL=1
+endif
+
+sanity: test-dep verify-no-running-vpp
+ @sys_req/dev_shm_size.sh
+ @bash -c "test $(PARALLEL_ILLEGAL) -eq 0 ||\
+ (echo \"*******************************************************************\" &&\
+ echo \"* Sanity check failed, TEST_JOBS is not 1 or 'auto' and DEBUG, STEP or PROFILE is set\" &&\
+ echo \"*******************************************************************\" &&\
+ false)"
+ @bash -c "$(SANITY_IMPORT_VPP_PAPI_CMD) ||\
+ (echo \"*******************************************************************\" &&\
+ echo \"* Sanity check failed, cannot import vpp_papi\" &&\
+ echo \"* to debug: \" &&\
+ echo \"* 1. enter test shell: make test-shell\" &&\
+ echo \"* 2. execute debugger: gdb python -ex 'run sanity_import_vpp_papi.py'\" &&\
+ echo \"*******************************************************************\" &&\
+ false)"
+ @bash -c "$(SANITY_RUN_VPP_CMD) ||\
+ (echo \"*******************************************************************\" &&\
+ echo \"* Sanity check failed, cannot run vpp\" &&\
+ echo \"*******************************************************************\" &&\
+ false)"
+
+.PHONY: ext-test-apps
+ext-test-apps:
+ make -C ext test-apps
+
+$(BUILD_TEST_SRC): verify-env
+ @mkdir -p $@
+ @for file in $(VPP_TEST_SRC); do if [ ! -e $(BUILD_TEST_SRC)/$$(basename $$file) ] ; then ln -s $$file $(BUILD_TEST_SRC) ; fi ; done
+
+$(FAILED_DIR): reset
+ @mkdir -p $@
+
+.PHONY: test-dep
+test-dep: $(BUILD_TEST_SRC) $(PAPI_INSTALL_DONE) $(FAILED_DIR)
+
+.PHONY: test
+test: test-dep ext-test-apps sanity
+ $(call retest-func)
+
+.PHONY: retest
+retest: verify-env sanity $(FAILED_DIR)
+ $(call retest-func)
+
+.PHONY: shell
+shell: test-dep
+ @echo "source $(VENV_PATH)/bin/activate;\
+ cd $(BUILD_TEST_SRC);\
+ export PYTHONPATH=$(BUILD_TEST_SRC);\
+ export RND_SEED=$(RND_SEED);\
+ echo '***';\
+ echo PYTHONPATH=$(BUILD_TEST_SRC);\
+ echo RND_SEED=$(RND_SEED);\
+ echo VPP_BUILD_DIR=$(VPP_BUILD_DIR);\
+ echo VPP_BIN=$(VPP_BIN);\
+ echo VPP_PLUGIN_PATH=$(VPP_PLUGIN_PATH);\
+ echo VPP_TEST_PLUGIN_PATH=$(VPP_TEST_PLUGIN_PATH);\
+ echo VPP_INSTALL_PATH=$(VPP_INSTALL_PATH);\
+ echo EXTERN_TESTS=$(EXTERN_TESTS);\
+ echo EXTERN_PLUGINS=$(EXTERN_PLUGINS);\
+ echo EXTERN_COV_DIR=$(EXTERN_COV_DIR);\
+ echo LD_LIBRARY_PATH=$(LD_LIBRARY_PATH);\
+ echo '***';\
+ exec </dev/tty" | bash -i
+
+.PHONY: reset
+reset: