From b0158f91d3e1285b1a6230f1972d317c52263352 Mon Sep 17 00:00:00 2001 From: Yurii Lisovskyi Date: Thu, 2 Nov 2023 15:03:49 +0200 Subject: [PATCH] Add SAI attrs usage in test logging Signed-off-by: Yurii Lisovskyi --- common/sai.py | 2 ++ .../sai_redis_client/sai_redis_client.py | 5 +++ .../sai_thrift_client/sai_thrift_client.py | 5 +++ common/sai_logger.py | 31 +++++++++++++++++++ tests/conftest.py | 18 +++++++++++ 5 files changed, 61 insertions(+) create mode 100644 common/sai_logger.py diff --git a/common/sai.py b/common/sai.py index c922721b..2736d514 100644 --- a/common/sai.py +++ b/common/sai.py @@ -5,6 +5,7 @@ from saichallenger.common.sai_client.sai_client import SaiClient from saichallenger.common.sai_data import SaiObjType +from saichallenger.common.sai_logger import SaiAttrsJsonLogger class CommandProcessor: @@ -241,6 +242,7 @@ def get(self, obj, attrs, do_assert=True): attr = attrs[0] attr_type = self.get_obj_attr_type(obj_type, attr) status, data = self.get_by_type(obj, attr, attr_type) + SaiAttrsJsonLogger.insert_attr_use(obj_type, attr, "get") if do_assert: assert status == "SAI_STATUS_SUCCESS", f"Failed to retrieve {attr}: {status}" return data diff --git a/common/sai_client/sai_redis_client/sai_redis_client.py b/common/sai_client/sai_redis_client/sai_redis_client.py index ab48f5ac..1d0662b6 100644 --- a/common/sai_client/sai_redis_client/sai_redis_client.py +++ b/common/sai_client/sai_redis_client/sai_redis_client.py @@ -5,6 +5,7 @@ from saichallenger.common.sai_client.sai_client import SaiClient from saichallenger.common.sai_data import SaiObjType, SaiData +from saichallenger.common.sai_logger import SaiAttrsJsonLogger class SaiRedisClient(SaiClient): @@ -120,6 +121,10 @@ def operate(self, obj, attrs, op): self.r.delete("GETRESPONSE_KEY_VALUE_OP_QUEUE") assert len(status) == 3, f"SAI \"{op[1:]}\" operation failure!" + attrs_list = json.loads(attrs) + if attrs_list: + for attr in attrs_list[::2]: + SaiAttrsJsonLogger.insert_attr_use(obj.split(":")[0], attr, op[1:]) return status def create(self, obj, attrs, do_assert=True): diff --git a/common/sai_client/sai_thrift_client/sai_thrift_client.py b/common/sai_client/sai_thrift_client/sai_thrift_client.py index 014d2688..937d4460 100644 --- a/common/sai_client/sai_thrift_client/sai_thrift_client.py +++ b/common/sai_client/sai_thrift_client/sai_thrift_client.py @@ -8,6 +8,7 @@ from saichallenger.common.sai_client.sai_thrift_client.sai_thrift_utils import * from saichallenger.common.sai_data import SaiData from saichallenger.common.sai_data import SaiObjType +from saichallenger.common.sai_logger import SaiAttrsJsonLogger from sai_thrift import sai_rpc, sai_adapter from thrift.protocol import TBinaryProtocol from thrift.transport import TSocket, TTransport @@ -164,6 +165,10 @@ def _operate(self, operation, attrs=(), oid=None, obj_type=None, key=None): result = key if key is not None else result else: result = None + + for attr in attrs[::2]: + SaiAttrsJsonLogger.insert_attr_use(f"SAI_OBJECT_TYPE_{obj_type_name.upper()}", attr, operation) + return status, result def _operate_attributes(self, operation, attrs=(), oid=None, obj_type=None, key=None): diff --git a/common/sai_logger.py b/common/sai_logger.py new file mode 100644 index 00000000..9dfe76d2 --- /dev/null +++ b/common/sai_logger.py @@ -0,0 +1,31 @@ +import json +import os + + +class SaiAttrsJsonLogger: + + used_attrs_json = dict() + + @classmethod + def dump(cls, log_path=None) -> None: + log_file_path = log_path or os.path.join(os.path.dirname(os.path.realpath(__file__)), 'tests', 'sai_attrs.json') + with open(log_file_path, '+w') as log_fp: + json.dump(cls.used_attrs_json, log_fp, indent=4) + + @classmethod + def insert_attr_use(cls, obj_type, attr_name, oper): + test_name = os.environ.get('PYTEST_CURRENT_TEST').split(':')[-1].split(' ')[0] + cls.used_attrs_json[obj_type] = cls.used_attrs_json.get(obj_type, None) or dict() + cls.used_attrs_json[obj_type][oper] = cls.used_attrs_json[obj_type].get(oper, None) or dict() + cls.used_attrs_json[obj_type][oper][attr_name] = cls.used_attrs_json[obj_type][oper].get(attr_name, None) or dict() + cls.used_attrs_json[obj_type][oper][attr_name][test_name] = "passed" + + @classmethod + def update_test_result(cls, cur_test_name, result): + for obj_type in cls.used_attrs_json: + for oper in cls.used_attrs_json[obj_type]: + for attr_name in cls.used_attrs_json[obj_type][oper]: + for test_name in cls.used_attrs_json[obj_type][oper][attr_name]: + if test_name == cur_test_name: + cls.used_attrs_json[obj_type][oper][attr_name][test_name] = result + diff --git a/tests/conftest.py b/tests/conftest.py index c7f5f483..343d85ab 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,8 +7,10 @@ from saichallenger.common.sai_phy import SaiPhy from saichallenger.common.sai_testbed import SaiTestbed from saichallenger.common.sai_data import SaiObjType +from saichallenger.common.sai_logger import SaiAttrsJsonLogger _previous_test_failed = False +log_attrs = False @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): @@ -40,6 +42,17 @@ def pytest_runtest_makereport(item, call): elif not _previous_test_failed: # Update the outcome only in case all previous phases were successful _previous_test_failed = rep.outcome not in ["passed", "skipped"] + + if log_attrs: + log_file_path = f"{curdir}/sai_attr_log.json" + SaiAttrsJsonLogger.dump(log_file_path) + + +@pytest.hookimpl +def pytest_report_teststatus(report): + if report.when == "call": + if report.outcome == "failed" and log_attrs: + SaiAttrsJsonLogger.update_test_result(report.head_line, report.outcome) @pytest.fixture @@ -51,6 +64,7 @@ def prev_test_failed(): def pytest_addoption(parser): parser.addoption("--traffic", action="store_true", help="run tests with traffic") parser.addoption("--testbed", action="store", help="Testbed name", required=True) + parser.addoption("--log_attrs", action="store_true", help="run tests with traffic") def pytest_sessionstart(session): @@ -64,7 +78,11 @@ def exec_params(request): # Generic parameters "traffic": request.config.getoption("--traffic"), "testbed": request.config.getoption("--testbed"), + "log_attrs": request.config.getoption("--log_attrs"), } + if config_param["log_attrs"]: + global log_attrs + log_attrs = True return config_param