From dc0453b3a97feb02e66e4888e8d071e8116aa806 Mon Sep 17 00:00:00 2001 From: Michal Cmarada Date: Fri, 8 Feb 2019 12:28:09 +0100 Subject: add test and checkstyle support All tests are in "tests" directory. To run tests use: make test For verbose output use: export V=2;make test ARGS="-V" Test log file is generated in: Testing/Temporary/LastTest.log To run checkstyle for the current commit use: ./scripts/checkstyle.sh To run full check on all files use: ./scripts/checkstyle.sh --full Change-Id: Ic83b3dbd44d2a264d27935f4e65cf9e737cfc0a0 Signed-off-by: Michal Cmarada --- tests/list_tests.py | 35 +++++++++++ tests/log.py | 101 +++++++++++++++++++++++++++++++ tests/requirements.txt | 26 ++++++++ tests/test_jvpp.py | 160 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 322 insertions(+) create mode 100644 tests/list_tests.py create mode 100644 tests/log.py create mode 100644 tests/requirements.txt create mode 100644 tests/test_jvpp.py (limited to 'tests') diff --git a/tests/list_tests.py b/tests/list_tests.py new file mode 100644 index 0000000..35c94b4 --- /dev/null +++ b/tests/list_tests.py @@ -0,0 +1,35 @@ +# Copyright (c) 2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest + + +def main(): + """Discovers unittests in current directory and prints them as list of tests. + + Example: + Parse test function name 'test_vpp_acl_callback_api (test_jvpp.TestJVpp)' to test descriptor: + test_jvpp.TestJVpp.test_vpp_acl_callback_api + + """ + suite = unittest.TestLoader().discover("") + for root_test in suite: + tests = root_test._tests + for parent_test in tests: + for jvpp_test in parent_test._tests: + test_name = jvpp_test.__str__().split() + print(test_name[1][1:-1] + "." + test_name[0]) + + +if __name__ == "__main__": + main() diff --git a/tests/log.py b/tests/log.py new file mode 100644 index 0000000..aaffa3f --- /dev/null +++ b/tests/log.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python + +# Copyright (c) 2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os +import logging + +""" @var formatting delimiter consisting of '=' characters """ +double_line_delim = '=' * 78 +""" @var formatting delimiter consisting of '-' characters """ +single_line_delim = '-' * 78 + + +def colorize(msg, color): + return color + msg + COLOR_RESET + + +class ColorFormatter(logging.Formatter): + + def init(self, fmt=None, datefmt=None): + super(ColorFormatter, self).__init__(fmt, datefmt) + + def format(self, record): + message = super(ColorFormatter, self).format(record) + if hasattr(record, 'color'): + message = colorize(message, record.color) + return message + + +try: + verbose = int(os.getenv("V", 0)) +except: + verbose = 0 + +# 40 = ERROR, 30 = WARNING, 20 = INFO, 10 = DEBUG, 0 = NOTSET (all messages) +if verbose >= 2: + log_level = 10 +elif verbose == 1: + log_level = 20 +else: + log_level = 40 + +handler = logging.StreamHandler(sys.stdout) +color_formatter = ColorFormatter(fmt='%(asctime)s,%(msecs)03d %(message)s', + datefmt="%H:%M:%S") +handler.setFormatter(color_formatter) +handler.setLevel(log_level) + +global_logger = logging.getLogger() +global_logger.addHandler(handler) + +scapy_logger = logging.getLogger("scapy.runtime") +scapy_logger.setLevel(logging.ERROR) + + +def get_logger(name): + logger = logging.getLogger(name) + logger.setLevel(logging.DEBUG) + return logger + + +def get_parallel_logger(stream): + logger = logging.getLogger('parallel_logger_{}'.format(stream)) + logger.propagate = False + logger.setLevel(logging.DEBUG) + handler = logging.StreamHandler(stream) + handler.setFormatter(color_formatter) + handler.setLevel(log_level) + logger.addHandler(handler) + return logger + + +# Static variables to store color formatting strings. +# +# These variables (RED, GREEN, YELLOW and LPURPLE) are used to configure +# the color of the text to be printed in the terminal. Variable COLOR_RESET +# is used to revert the text color to the default one. +if hasattr(sys.stdout, 'isatty') and sys.stdout.isatty(): + RED = '\033[91m' + GREEN = '\033[92m' + YELLOW = '\033[93m' + LPURPLE = '\033[94m' + COLOR_RESET = '\033[0m' +else: + RED = '' + GREEN = '' + YELLOW = '' + LPURPLE = '' + COLOR_RESET = '' diff --git a/tests/requirements.txt b/tests/requirements.txt new file mode 100644 index 0000000..2b15d01 --- /dev/null +++ b/tests/requirements.txt @@ -0,0 +1,26 @@ +# Copyright (c) 2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cffi # MIT +cryptography!=2.0 # BSD/Apache-2.0 +faulthandler; python_version < '3.3' # # BSD License (2 clause) +flake8 # MIT +ipaddress; python_version < '3.3' # PSF +parameterized>=0.6.1 # BSD +pexpect # ISC +psutil # BSD +pycodestyle # MIT (Expat license) https://pypi.org/project/pycodestyle/ +scapy==2.4.0; python_version >= '2.7' or python_version >= '3.4' # GPL2 https://github.com/secdev/scapy/blob/master/LICENSE +six # MIT +subprocess32 # PSF +syslog_rfc5424_parser>=0.3.0 # ISC diff --git a/tests/test_jvpp.py b/tests/test_jvpp.py new file mode 100644 index 0000000..862b285 --- /dev/null +++ b/tests/test_jvpp.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python + +# Copyright (c) 2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import subprocess +import unittest +from log import get_logger + +API_FILES_PATH = "java/" + +# Registry jar file name prefix +REGISTRY_JAR_PREFIX = "jvpp-registry" + + +class TestJVpp(unittest.TestCase): + """ JVPP Core Test Case """ + + def invoke_for_jvpp_core(self, api_jar_name, test_class_name): + self.jvpp_connection_test(api_jar_name=api_jar_name, + test_class_name=test_class_name) + + def test_vpp_core_callback_api(self): + """ JVPP Core Callback Api Test Case """ + self.invoke_for_jvpp_core(api_jar_name="jvpp-core", + test_class_name="io.fd.jvpp.core.test." + "CallbackApiTest") + + def test_vpp_registry_callback_api(self): + """ JVPP Core Callback Api Test Case """ + self.invoke_for_jvpp_core(api_jar_name="jvpp-registry", + test_class_name="io.fd.jvpp.test." + "ConnectionTest") + + def test_vpp_core_future_api(self): + """JVPP Core Future Api Test Case""" + self.invoke_for_jvpp_core(api_jar_name="jvpp-core", + test_class_name="io.fd.jvpp.core.test." + "FutureApiTest") + + def test_vpp_acl_callback_api(self): + """ JVPP Acl Callback Api Test Case """ + self.invoke_for_jvpp_core(api_jar_name="jvpp-acl", + test_class_name="io.fd.jvpp.acl.test." + "CallbackApiTest") + + def test_vpp_acl_future_api(self): + """JVPP Acl Future Api Test Case""" + self.invoke_for_jvpp_core(api_jar_name="jvpp-acl", + test_class_name="io.fd.jvpp.acl.test." + "FutureApiTest") + + def test_vpp_ioamexport_callback_api(self): + """ JVPP Ioamexport Callback Api Test Case """ + self.invoke_for_jvpp_core(api_jar_name="jvpp-ioamexport", + test_class_name="io.fd.jvpp.ioamexport." + "test.CallbackApiTest") + + def test_vpp_ioamexport_future_api(self): + """JVPP Ioamexport Future Api Test Case""" + self.invoke_for_jvpp_core(api_jar_name="jvpp-ioamexport", + test_class_name="io.fd.jvpp.ioamexport." + "test.FutureApiTest") + + def test_vpp_ioampot_callback_api(self): + """ JVPP Ioampot Callback Api Test Case """ + self.invoke_for_jvpp_core(api_jar_name="jvpp-ioampot", + test_class_name="io.fd.jvpp.ioampot." + "test.CallbackApiTest") + + def test_vpp_ioampot_future_api(self): + """JVPP Ioampot Future Api Test Case""" + self.invoke_for_jvpp_core(api_jar_name="jvpp-ioampot", + test_class_name="io.fd.jvpp.ioampot." + "test.FutureApiTest") + + def test_vpp_ioamtrace_callback_api(self): + """ JVPP Ioamtrace Callback Api Test Case """ + self.invoke_for_jvpp_core(api_jar_name="jvpp-ioamtrace", + test_class_name="io.fd.jvpp.ioamtrace." + "test.CallbackApiTest") + + def test_vpp_ioamtrace_future_api(self): + """JVPP Ioamtrace Future Api Test Case""" + self.invoke_for_jvpp_core(api_jar_name="jvpp-ioamtrace", + test_class_name="io.fd.jvpp.ioamtrace." + "test.FutureApiTest") + + def test_vpp_snat_callback_api(self): + """ JVPP Snat Callback Api Test Case """ + self.invoke_for_jvpp_core(api_jar_name="jvpp-nat", + test_class_name="io.fd.jvpp.nat.test." + "CallbackApiTest") + + def test_vpp_snat_future_api(self): + """JVPP Snat Future Api Test Case""" + self.invoke_for_jvpp_core(api_jar_name="jvpp-nat", + test_class_name="io.fd.jvpp.nat.test." + "FutureApiTest") + + @staticmethod + def full_jar_name(install_dir, jar_name, version): + return os.path.join(install_dir, API_FILES_PATH, + "{0}-{1}.jar".format(jar_name, version)) + + def jvpp_connection_test(self, api_jar_name, test_class_name): + self.logger = get_logger(api_jar_name) + install_dir = os.path.abspath('..') + self.logger.info("Install directory : {0}".format(install_dir)) + self.shm_prefix = "honeycomb" + proc = subprocess.Popen(['../version'], stdout=subprocess.PIPE) + version = proc.stdout.read().split("-")[0] + registry_jar_path = self.full_jar_name(install_dir, REGISTRY_JAR_PREFIX, version) + self.logger.info("JVpp Registry jar path : {0}".format(registry_jar_path)) + if not os.path.isfile(registry_jar_path): + raise Exception( + "JVpp Registry jar has not been found: {0}" + .format(registry_jar_path)) + + api_jar_path = self.full_jar_name(install_dir, api_jar_name, version) + self.logger.info("Api jar path : {0}".format(api_jar_path)) + if not os.path.isfile(api_jar_path): + raise Exception( + "Api jar has not been found: {0}".format(api_jar_path)) + + # passes shm prefix as parameter to create connection with same value + command = ["sudo", "java", "-cp", + "{0}:{1}".format(registry_jar_path, api_jar_path), + test_class_name, "/vpe-api"] + + self.process = subprocess.Popen(command, shell=False, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, bufsize=1, + universal_newlines=True) + + out, err = self.process.communicate() + self.logger.info("Process output : {0}{1}".format(os.linesep, out)) + + if self.process.returncode != 0: + raise subprocess.CalledProcessError(self.process.returncode, command, + "Command {0} failed with return code: {1}.{2}" + "Process error output: {2}{3}" + .format(command, self.process.returncode, os.linesep, err)) + + def tearDown(self): + self.logger.info("Tearing down jvpp test") + super(TestJVpp, self).tearDown() + if hasattr(self, 'process') and self.process.poll() is None: + self.process.kill() -- cgit 1.2.3-korg