[igt-dev] [PATCH RFC 2/3] scripts/igt_doc.py: add a logic to generate Intel CI testlists

Kamil Konieczny kamil.konieczny at linux.intel.com
Wed Nov 29 12:47:31 UTC 2023


Hi Mauro,
On 2023-11-28 at 17:43:02 +0100, Mauro Carvalho Chehab wrote:
> From: Mauro Carvalho Chehab <mchehab at kernel.org>
> 
> Testlist for Intel CI requires parsing not only IGT testlists,
> but also block and permit lists. This is currently handled
> internally, but not from the documentation.

Remove comma before "but", s/, but/ but/

> 
> Now that we have everything set in place, add a method for
> generating it at IGT. The logic there is somewhat generic,

Same here, remove comma.

> but it expects some fields with a namespace as defined on
> tests/intel/*.json files.
> 
> So, instead of placing at the generic code (test_list.py),

s/So, instead/Instead/

> add them to igt_doc.py, where IGT-specific glue can easily
> be added while keeping test_list.py generic enought to be
--------------------------------------------- ^^^^^^^
s/enought/enough

With this,
Acked-by: Kamil Konieczny <kamil.konieczny at linux.intel.com>

> used on other projects.
> 
> Signed-off-by: Mauro Carvalho Chehab <mchehab at kernel.org>
> ---
>  scripts/igt_doc.py   | 148 ++++++++++++++++++++++++++++++++++++++++++-
>  scripts/test_list.py |   3 +
>  2 files changed, 150 insertions(+), 1 deletion(-)
> 
> diff --git a/scripts/igt_doc.py b/scripts/igt_doc.py
> index ab6179366831..a807d2bb373d 100755
> --- a/scripts/igt_doc.py
> +++ b/scripts/igt_doc.py
> @@ -11,10 +11,150 @@
>  """Maintain test plan and test implementation documentation on IGT."""
>  
>  import argparse
> +import os
> +import re
>  import sys
>  
>  from test_list import TestList
>  
> +class IgtTestList(TestList):
> +    """
> +        This class implements testlist generation as expected by Intel CI.
> +        It does that by handling test lists split by "Run type" and
> +        using GPU (or configuration) specific fields, being "GPU" for a
> +        permit list of tests, and "GPU excluded platform" for a block
> +        list of tests.
> +
> +        The logic below has "priority zero" rules, which are:
> +
> +        - if the test is not on any block lists nor it contains
> +          "GPU" or "GPU excluded platform", it won't be blocked;
> +        - if the test is in "all" block list, it will be blocked for all
> +          GPUs. Values from "GPU" and "GPU excluded platform" will be ignored.
> +
> +        If none of the above rules apply, it will handle GPU positive
> +        and negative rules:
> +
> +        - if "GPU" field is present on such test, the default is
> +          is to block the test (default_gpu_value = False). If not
> +          present, the default is to not block (default_gpu_value = True).
> +
> +        Now, it will check for "GPU" and "GPU excluded platform":
> +
> +        - it sets the default according to default_gpu_value.
> +
> +        Then:
> +
> +        - if "GPU" exists, for each GPU listed on the list, it will
> +          unblock the test;
> +        - if "GPU excluded platform" exists, for each GPU listed on
> +          the list, it will block the test.
> +    """
> +    def gen_intelci_testlist(self): #pylint: disable=R0912
> +        """Return a list of gpu configs and testlists."""
> +
> +        subtest_dict = self.expand_dictionary(True)
> +
> +        # Create a tests_per_list dict
> +        gpus = set()
> +        tests_per_list = {}
> +        split_regex = re.compile(r",\s*")
> +
> +        for subname, subtest in subtest_dict.items():
> +            run_type = subtest.get("Run type", "other")
> +
> +            run_type_set = set(split_regex.split(run_type))
> +            for run_type in run_type_set:
> +                if run_type not in tests_per_list:
> +                    tests_per_list[run_type] = {}
> +
> +                if subname not in tests_per_list[run_type]:
> +                    tests_per_list[run_type][subname] = {}
> +
> +                if "GPU" in subtest:
> +                    for gpu_list in split_regex.split(subtest["GPU"]):
> +                        gpus.add(gpu_list)
> +                        tests_per_list[run_type][subname][gpu_list] = True
> +
> +                if "GPU excluded platform" in subtest:
> +                    for gpu_list in split_regex.split(subtest["GPU excluded platform"]):
> +                        gpus.add(gpu_list)
> +                        tests_per_list[run_type][subname][gpu_list] = False
> +
> +        # Handle block and permit lists
> +
> +        for run_type in tests_per_list.keys(): # pylint: disable=C0201,C0206
> +            for subname, gpu in tests_per_list[run_type].items():
> +
> +                # Trivial case: fields not defined
> +                if not gpus:
> +                    tests_per_list[run_type][subname]["all"] = True
> +                    continue
> +
> +                if not gpu:
> +                    tests_per_list[run_type][subname] = {}
> +                    for gpu in gpus:
> +                        tests_per_list[run_type][subname][gpu] = True
> +                    continue
> +
> +                default_gpu_value = True
> +                for gpu, value in tests_per_list[run_type][subname].items():
> +                    if value:
> +                        default_gpu_value = False
> +                        break
> +                    if not gpu in tests_per_list[run_type][subname]:
> +                        for gpu in gpus:
> +                            tests_per_list[run_type][subname][gpu] = default_gpu_value
> +
> +                if "all" in tests_per_list[run_type][subname]:
> +                    if not tests_per_list[run_type][subname]["all"]:
> +                        for gpu in gpus:
> +                            tests_per_list[run_type][subname][gpu] = False
> +
> +        return (gpus, tests_per_list)
> +
> +    def write_intelci_testlist(self, directory):
> +        '''Create testlist directory (if needed) and files'''
> +
> +        if not os.path.exists(directory):
> +            os.makedirs(directory)
> +
> +        (gpus, tests_per_list)  = self.gen_intelci_testlist()
> +        testlists = {}
> +
> +        for run_type in tests_per_list.keys(): # pylint: disable=C0201,C0206
> +            for subname, gpu_dict in tests_per_list[run_type].items():
> +                for gpu, value in gpu_dict.items():
> +                    run_name = re.sub(r"[\W_]+", "-", run_type)
> +                    gpu = re.sub(r"[\W_]+", "-", gpu)
> +
> +                    if gpus:
> +                        name = f"{run_name}_{gpu}".lower()
> +                    else:
> +                        name = run_name.lower()
> +
> +                    if not name.startswith(self.driver_name.lower()):
> +                        name = f"{self.driver_name.lower()}_{name}"
> +
> +                    name = re.sub(r"_+", "_", name)
> +
> +                    if name not in testlists:
> +                        testlists[name] = set()
> +
> +                    if value:
> +                        testlists[name].add(subname)
> +
> +        for testlist, subtests in testlists.items():
> +            if testlist == "":
> +                testlist = "other"
> +
> +
> +            fname = os.path.join(directory, testlist) + ".testlist"
> +            with open(fname, 'w', encoding='utf8') as handler:
> +                for sub in sorted(subtests):
> +                    handler.write (f"{sub}\n")
> +                print(f"{fname} created.")
> +
>  def main():
>      """
>      Main logic
> @@ -48,12 +188,14 @@ def main():
>                          default=igt_build_path)
>      parser.add_argument("--gen-testlist",
>                          help="Generate documentation at the GEN_TESTLIST directory, using SORT_FIELD to split the tests. Requires --sort-field.")
> +    parser.add_argument("--intelci-testlist",
> +                        help="Generate testlists for Intel CI integration at the INTELCI_TESTLIST directory.")
>      parser.add_argument('--files', nargs='+',
>                          help="File name(s) to be processed")
>  
>      parse_args = parser.parse_args()
>  
> -    tests = TestList(config_fname = parse_args.config,
> +    tests = IgtTestList(config_fname = parse_args.config,
>                          include_plan = parse_args.include_plan,
>                          file_list = parse_args.files,
>                          igt_build_path = parse_args.igt_build_path)
> @@ -77,6 +219,10 @@ def main():
>              sys.exit("Need a field to split the testlists")
>          tests.gen_testlist(parse_args.gen_testlist, parse_args.sort_field)
>  
> +    if parse_args.intelci_testlist:
> +        run = True
> +        tests.write_intelci_testlist(parse_args.intelci_testlist)
> +
>      if parse_args.to_json:
>          run = True
>          tests.print_json(parse_args.to_json)
> diff --git a/scripts/test_list.py b/scripts/test_list.py
> index 3954e883ada3..36eea5fb1c76 100644
> --- a/scripts/test_list.py
> +++ b/scripts/test_list.py
> @@ -263,6 +263,7 @@ class TestList:
>          self.filters = {}
>          self.subtest_separator = subtest_separator
>          self.main_name = main_name
> +        self.driver_name = ""
>  
>          self.internal_fields =  [ '_summary_', '_arg_', '_subtest_line_' ]
>  
> @@ -289,6 +290,8 @@ class TestList:
>              cfg_path = "./"
>              driver_name = main_name
>  
> +        self.driver_name = driver_name
> +
>          if sources_path:
>              cfg_path = os.path.realpath(sources_path) + "/"
>  
> -- 
> 2.42.0
> 


More information about the igt-dev mailing list