From d76d99af81585c10e778d761d862fca77a94bc35 Mon Sep 17 00:00:00 2001 From: Vratko Polak Date: Tue, 9 Mar 2021 14:22:34 +0100 Subject: [PATCH] API: Track options and version If options are not present in .api.json file (e.g. old PVP build), use an empty dict. If a message is used in CSIT, check its options. Tolerate vat_help, but print warning for others. This aims to discover in-progress and obsolete APIs. If .api.json version is not detected, or starts with "0.", add a "version" item to options, so they get reported. Change-Id: Ic5a9423157728a58f7ad306c7bd9eaef3bd92488 Signed-off-by: Vratko Polak --- resources/libraries/python/VppApiCrc.py | 64 ++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/resources/libraries/python/VppApiCrc.py b/resources/libraries/python/VppApiCrc.py index 693dac064a..94e2690d8b 100644 --- a/resources/libraries/python/VppApiCrc.py +++ b/resources/libraries/python/VppApiCrc.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019 Cisco and/or its affiliates. +# Copyright (c) 2021 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: @@ -84,6 +84,12 @@ class VppApiCrcChecker: This gets populated with CRCs found in .api.json, to serve as a hint when reporting errors.""" + self._options = dict() + """Mapping from API name to options dictionary. + + This gets populated with options found in .api.json, + to serve as a hint when reporting errors.""" + self._reported = dict() """Mapping from API name to CRC string. @@ -171,7 +177,34 @@ class VppApiCrcChecker: return _str(crc) raise RuntimeError(f"No CRC found for message: {msg_obj!r}") - def _process_crc(self, api_name, crc): + @staticmethod + def _get_options(msg_obj, version): + """Utility function to extract API options from an intermediate json. + + Empty dict is returned if options are not found, + so old VPP builds can be tested without spamming. + If version starts with "0.", add a fake option, + as the message is treated as "in-progress" by the API upgrade process. + + :param msg_obj: Loaded json object, item of "messages" list. + :param version: Version string from the .api.json file. + :type msg_obj: list of various types + :type version: Optional[str] + :returns: Object found as value for "options" key. + :rtype: dict + """ + options = dict() + for item in reversed(msg_obj): + if not isinstance(item, dict): + continue + options = item.get(u"options", None) + if options is not None: + break + if version is None or version.startswith(u"0."): + options[u"version"] = version + return options + + def _process_crc(self, api_name, crc, options): """Compare API to verified collections, update class state. Here, API stands for (message name, CRC) pair. @@ -195,16 +228,21 @@ class VppApiCrcChecker: Attempts to overwrite value in _found or _reported should not happen, so the code does not check for that, simply overwriting. + Options are stored, to be examined later. + The intended usage is to call this method multiple times, and then raise exception listing all _reported. :param api_name: API name to check. :param crc: Discovered CRC to check for the name. + :param options: Empty dict or options value for in .api.json :type api_name: str :type crc: str + :type options: dict """ # Regardless of the result, remember as found. self._found[api_name] = crc + self._options[api_name] = options old_expected = self._expected new_expected = old_expected.copy() for collection_name, name_to_crc_mapping in old_expected.items(): @@ -244,11 +282,13 @@ class VppApiCrcChecker: continue with open(f"{root}/{filename}", u"rt") as file_in: json_obj = json.load(file_in) + version = json_obj[u"options"].get(u"version", None) msgs = json_obj[u"messages"] for msg_obj in msgs: msg_name = self._get_name(msg_obj) msg_crc = self._get_crc(msg_obj) - self._process_crc(msg_name, msg_crc) + msg_options = self._get_options(msg_obj, version) + self._process_crc(msg_name, msg_crc, msg_options) logger.debug(f"Surviving collections: {self._expected.keys()!r}") def report_initial_conflicts(self, report_missing=False): @@ -295,6 +335,8 @@ class VppApiCrcChecker: def check_api_name(self, api_name): """Fail if the api_name has no, or different from known CRC associated. + Print warning if options contain anything more than vat_help. + Do not fail if this particular failure has been already reported. Intended use: Call during test (not in initialization), @@ -328,9 +370,13 @@ class VppApiCrcChecker: if name_to_crc_mapping[api_name] == crc: matching = True break - if matching: - return - self._reported[api_name] = crc - self.log_and_raise( - f"No active collection contains API {api_name!r} with CRC {crc!r}" - ) + if not matching: + self._reported[api_name] = crc + self.log_and_raise( + f"No active collection contains API {api_name!r} with CRC {crc!r}" + ) + options = self._options[api_name] + options.pop(u"vat_help", None) + if options: + self._reported[api_name] = crc + logger.console(f"{api_name} used but has options {options}") -- 2.16.6