tests: preload api files

When sanity test is not done, API files are not loaded until the
first test case is run. Hence, it is not possible to use enums, etc.
outside of a test class.
By preloading API files before running any tests, it prevents its
issue.

Type: fix
Change-Id: I8730150374e6c5f8d6933ec037811372ac2a8da0
Signed-off-by: Maxime Peim <mpeim@cisco.com>
This commit is contained in:
Maxime Peim
2023-11-14 15:26:41 +01:00
committed by Dave Wallace
parent 87241fefd9
commit 77caeb1b19
6 changed files with 54 additions and 38 deletions

View File

@ -24,8 +24,7 @@ from vpp_papi import vpp_transport_shmem
class TestVppPapiVPPApiClient(unittest.TestCase):
def test_getcontext(self):
vpp_papi.VPPApiClient.apidir = "."
c = vpp_papi.VPPApiClient(testmode=True, use_socket=True)
c = vpp_papi.VPPApiClient(apidir=".", testmode=True, use_socket=True)
# reset initialization at module load time.
c.get_context.context = mp.Value(ctypes.c_uint, 0)
@ -39,8 +38,7 @@ class TestVppPapiVPPApiClientMp(unittest.TestCase):
# run_tests.py (eg. make test TEST_JOBS=10)
def test_get_context_mp(self):
vpp_papi.VPPApiClient.apidir = "."
c = vpp_papi.VPPApiClient(testmode=True, use_socket=True)
c = vpp_papi.VPPApiClient(apidir=".", testmode=True, use_socket=True)
# reset initialization at module load time.
c.get_context.context = mp.Value(ctypes.c_uint, 0)

View File

@ -281,16 +281,15 @@ class VPPApiJSONFiles:
@classmethod
def process_json_file(self, apidef_file):
api = json.load(apidef_file)
return self._process_json(api)
return self._process_json(apidef_file.read())
@classmethod
def process_json_str(self, json_str):
api = json.loads(json_str)
return self._process_json(api)
return self._process_json(json_str)
@staticmethod
def _process_json(api): # -> Tuple[Dict, Dict]
def _process_json(json_str): # -> Tuple[Dict, Dict]
api = json.loads(json_str)
types = {}
services = {}
messages = {}
@ -380,6 +379,30 @@ class VPPApiJSONFiles:
pass
return messages, services
@staticmethod
def load_api(apifiles=None, apidir=None):
messages = {}
services = {}
if not apifiles:
# Pick up API definitions from default directory
try:
if isinstance(apidir, list):
apifiles = []
for d in apidir:
apifiles += VPPApiJSONFiles.find_api_files(d)
else:
apifiles = VPPApiJSONFiles.find_api_files(apidir)
except (RuntimeError, VPPApiError):
raise VPPRuntimeError
for file in apifiles:
with open(file) as apidef_file:
m, s = VPPApiJSONFiles.process_json_file(apidef_file)
messages.update(m)
services.update(s)
return apifiles, messages, services
class VPPApiClient:
"""VPP interface.
@ -394,7 +417,6 @@ class VPPApiClient:
these messages in a background thread.
"""
apidir = None
VPPApiError = VPPApiError
VPPRuntimeError = VPPRuntimeError
VPPValueError = VPPValueError
@ -405,6 +427,7 @@ class VPPApiClient:
self,
*,
apifiles=None,
apidir=None,
testmode=False,
async_thread=True,
logger=None,
@ -439,6 +462,7 @@ class VPPApiClient:
self.id_msgdef = []
self.header = VPPType("header", [["u16", "msgid"], ["u32", "client_index"]])
self.apifiles = []
self.apidir = apidir
self.event_callback = None
self.message_queue = queue.Queue()
self.read_timeout = read_timeout
@ -449,29 +473,15 @@ class VPPApiClient:
self._apifiles = apifiles
self.stats = {}
if not apifiles:
# Pick up API definitions from default directory
try:
if isinstance(self.apidir, list):
apifiles = []
for d in self.apidir:
apifiles += VPPApiJSONFiles.find_api_files(d)
else:
apifiles = VPPApiJSONFiles.find_api_files(self.apidir)
except (RuntimeError, VPPApiError):
# In test mode we don't care that we can't find the API files
if testmode:
apifiles = []
else:
raise VPPRuntimeError
for file in apifiles:
with open(file) as apidef_file:
m, s = VPPApiJSONFiles.process_json_file(apidef_file)
self.messages.update(m)
self.services.update(s)
self.apifiles = apifiles
try:
self.apifiles, self.messages, self.services = VPPApiJSONFiles.load_api(
apifiles, apidir
)
except VPPRuntimeError as e:
if testmode:
self.apifiles = []
else:
raise e
# Basic sanity check
if len(self.messages) == 0 and not testmode:

View File

@ -259,6 +259,12 @@ ifneq ($(findstring $(DECODE_PCAPS),1 y yes),)
ARG18=--decode-pcaps
endif
ifneq ($(findstring $(API_PRELOAD),1 y yes),)
ARG19=--api-preload
else
ARG19=
endif
EXC_PLUGINS_ARG=
ifneq ($(VPP_EXCLUDED_PLUGINS),)
# convert the comma-separated list into N invocations of the argument to exclude a plugin
@ -267,7 +273,7 @@ endif
EXTRA_ARGS=$(ARG0) $(ARG1) $(ARG2) $(ARG3) $(ARG4) $(ARG5) $(ARG6) $(ARG7) $(ARG8) $(ARG9) $(ARG10) $(ARG11) $(ARG12) $(ARG13) $(ARG14) $(ARG15) $(ARG16) $(ARG17) $(ARG18)
EXTRA_ARGS=$(ARG0) $(ARG1) $(ARG2) $(ARG3) $(ARG4) $(ARG5) $(ARG6) $(ARG7) $(ARG8) $(ARG9) $(ARG10) $(ARG11) $(ARG12) $(ARG13) $(ARG14) $(ARG15) $(ARG16) $(ARG17) $(ARG18) $(ARG19)
RUN_TESTS_ARGS=--failed-dir=$(FAILED_DIR) --verbose=$(V) --jobs=$(TEST_JOBS) --filter=$(TEST) --retries=$(RETRIES) --venv-dir=$(VENV_PATH) --vpp-ws-dir=$(WS_ROOT) --vpp-tag=$(TAG) --rnd-seed=$(RND_SEED) --vpp-worker-count="$(VPP_WORKER_COUNT)" --keep-pcaps $(PLUGIN_PATH_ARGS) $(EXC_PLUGINS_ARG) $(TEST_PLUGIN_PATH_ARGS) $(EXTRA_ARGS)
RUN_SCRIPT_ARGS=--python-opts=$(PYTHON_OPTS)

View File

@ -201,6 +201,7 @@ parser.add_argument(
parser.add_argument(
"--sanity", action="store_true", help="perform sanity vpp run before running tests"
)
parser.add_argument("--api-preload", action="store_true", help="preload API files")
parser.add_argument(
"--force-foreground",

View File

@ -14,6 +14,7 @@ from multiprocessing import Process, Pipe, get_context
from multiprocessing.queues import Queue
from multiprocessing.managers import BaseManager
from config import config, num_cpus, available_cpus, max_vpp_cpus
from vpp_papi import VPPApiJSONFiles
from asfframework import (
VppTestRunner,
get_testcase_doc_name,
@ -906,6 +907,9 @@ def parse_results(results):
if __name__ == "__main__":
print(f"Config is: {config}")
if config.api_preload:
VPPApiJSONFiles.load_api(apidir=config.extern_apidir + [config.vpp_install_dir])
if config.sanity:
print("Running sanity test case.")
try:

View File

@ -236,11 +236,8 @@ class VppPapiProvider(object):
self._expect_api_retval = self._zero
self._expect_stack = []
# install_dir is a class attribute. We need to set it before
# calling the constructor.
VPPApiClient.apidir = config.extern_apidir + [config.vpp_install_dir]
self.vpp = VPPApiClient(
apidir=config.extern_apidir + [config.vpp_install_dir],
logger=test_class.logger,
read_timeout=read_timeout,
use_socket=True,