mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 11:45:06 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			269 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			269 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env python3
 | 
						|
# -*- coding: utf-8 eval: (blacken-mode 1) -*-
 | 
						|
#
 | 
						|
# July 9 2021, Christian Hopps <chopps@labn.net>
 | 
						|
#
 | 
						|
# Copyright (c) 2021, LabN Consulting, L.L.C.
 | 
						|
#
 | 
						|
# This program is free software; you can redistribute it and/or
 | 
						|
# modify it under the terms of the GNU General Public License
 | 
						|
# as published by the Free Software Foundation; either version 2
 | 
						|
# of the License, or (at your option) any later version.
 | 
						|
#
 | 
						|
# This program is distributed in the hope that it will be useful,
 | 
						|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
# GNU General Public License for more details.
 | 
						|
#
 | 
						|
# You should have received a copy of the GNU General Public License along
 | 
						|
# with this program; see the file COPYING; if not, write to the Free Software
 | 
						|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 | 
						|
#
 | 
						|
import argparse
 | 
						|
import glob
 | 
						|
import logging
 | 
						|
import os
 | 
						|
import re
 | 
						|
import subprocess
 | 
						|
import sys
 | 
						|
from collections import OrderedDict
 | 
						|
 | 
						|
import xmltodict
 | 
						|
 | 
						|
 | 
						|
def get_summary(results):
 | 
						|
    ntest = int(results["@tests"])
 | 
						|
    nfail = int(results["@failures"])
 | 
						|
    nerror = int(results["@errors"])
 | 
						|
    nskip = int(results["@skipped"])
 | 
						|
    npass = ntest - nfail - nskip - nerror
 | 
						|
    return ntest, npass, nfail, nerror, nskip
 | 
						|
 | 
						|
 | 
						|
def print_summary(results, args):
 | 
						|
    ntest, npass, nfail, nerror, nskip = (0, 0, 0, 0, 0)
 | 
						|
    for group in results:
 | 
						|
        _ntest, _npass, _nfail, _nerror, _nskip = get_summary(results[group])
 | 
						|
        if args.verbose:
 | 
						|
            print(
 | 
						|
                f"Group: {group} Total: {_ntest} PASSED: {_npass}"
 | 
						|
                " FAIL: {_nfail} ERROR: {_nerror} SKIP: {_nskip}"
 | 
						|
            )
 | 
						|
        ntest += _ntest
 | 
						|
        npass += _npass
 | 
						|
        nfail += _nfail
 | 
						|
        nerror += _nerror
 | 
						|
        nskip += _nskip
 | 
						|
    print(f"Total: {ntest} PASSED: {npass} FAIL: {nfail} ERROR: {nerror} SKIP: {nskip}")
 | 
						|
 | 
						|
 | 
						|
def get_global_testcase(results):
 | 
						|
    for group in results:
 | 
						|
        for testcase in results[group]["testcase"]:
 | 
						|
            if "@file" not in testcase:
 | 
						|
                return testcase
 | 
						|
    return None
 | 
						|
 | 
						|
 | 
						|
def get_filtered(tfilters, results, args):
 | 
						|
    if isinstance(tfilters, str) or tfilters is None:
 | 
						|
        tfilters = [tfilters]
 | 
						|
    found_files = OrderedDict()
 | 
						|
    for group in results:
 | 
						|
        if isinstance(results[group]["testcase"], list):
 | 
						|
            tlist = results[group]["testcase"]
 | 
						|
        else:
 | 
						|
            tlist = [results[group]["testcase"]]
 | 
						|
        for testcase in tlist:
 | 
						|
            for tfilter in tfilters:
 | 
						|
                if tfilter is None:
 | 
						|
                    if (
 | 
						|
                        "failure" not in testcase
 | 
						|
                        and "error" not in testcase
 | 
						|
                        and "skipped" not in testcase
 | 
						|
                    ):
 | 
						|
                        break
 | 
						|
                elif tfilter in testcase:
 | 
						|
                    break
 | 
						|
            else:
 | 
						|
                continue
 | 
						|
            # cname = testcase["@classname"]
 | 
						|
            fname = testcase.get("@file", "")
 | 
						|
            cname = testcase.get("@classname", "")
 | 
						|
            if not fname and not cname:
 | 
						|
                name = testcase.get("@name", "")
 | 
						|
                if not name:
 | 
						|
                    continue
 | 
						|
                # If we had a failure at the module level we could be here.
 | 
						|
                fname = name.replace(".", "/") + ".py"
 | 
						|
                tcname = fname
 | 
						|
            else:
 | 
						|
                if not fname:
 | 
						|
                    fname = cname.replace(".", "/") + ".py"
 | 
						|
                if args.files_only or "@name" not in testcase:
 | 
						|
                    tcname = fname
 | 
						|
                else:
 | 
						|
                    tcname = fname + "::" + testcase["@name"]
 | 
						|
            found_files[tcname] = testcase
 | 
						|
    return found_files
 | 
						|
 | 
						|
 | 
						|
def dump_testcase(testcase):
 | 
						|
    expand_keys = ("failure", "error", "skipped")
 | 
						|
 | 
						|
    s = ""
 | 
						|
    for key, val in testcase.items():
 | 
						|
        if isinstance(val, str) or isinstance(val, float) or isinstance(val, int):
 | 
						|
            s += "{}: {}\n".format(key, val)
 | 
						|
        else:
 | 
						|
            for k2, v2 in val.items():
 | 
						|
                s += "{}: {}\n".format(k2, v2)
 | 
						|
    return s
 | 
						|
 | 
						|
 | 
						|
def main():
 | 
						|
    parser = argparse.ArgumentParser()
 | 
						|
    parser.add_argument(
 | 
						|
        "-A",
 | 
						|
        "--save",
 | 
						|
        action="store_true",
 | 
						|
        help="Save /tmp/topotests{,.xml} in --rundir if --rundir does not yet exist",
 | 
						|
    )
 | 
						|
    parser.add_argument(
 | 
						|
        "-F",
 | 
						|
        "--files-only",
 | 
						|
        action="store_true",
 | 
						|
        help="print test file names rather than individual full testcase names",
 | 
						|
    )
 | 
						|
    parser.add_argument(
 | 
						|
        "-S",
 | 
						|
        "--select",
 | 
						|
        default="fe",
 | 
						|
        help="select results combination of letters: 'e'rrored 'f'ailed 'p'assed 's'kipped.",
 | 
						|
    )
 | 
						|
    parser.add_argument(
 | 
						|
        "-r",
 | 
						|
        "--results",
 | 
						|
        help="xml results file or directory containing xml results file",
 | 
						|
    )
 | 
						|
    parser.add_argument("--rundir", help=argparse.SUPPRESS)
 | 
						|
    parser.add_argument(
 | 
						|
        "-E",
 | 
						|
        "--enumerate",
 | 
						|
        action="store_true",
 | 
						|
        help="enumerate each item (results scoped)",
 | 
						|
    )
 | 
						|
    parser.add_argument("-T", "--test", help="print testcase at enumeration")
 | 
						|
    parser.add_argument(
 | 
						|
        "--errmsg", action="store_true", help="print testcase error message"
 | 
						|
    )
 | 
						|
    parser.add_argument(
 | 
						|
        "--errtext", action="store_true", help="print testcase error text"
 | 
						|
    )
 | 
						|
    parser.add_argument("--time", action="store_true", help="print testcase run times")
 | 
						|
 | 
						|
    parser.add_argument("-s", "--summary", action="store_true", help="print summary")
 | 
						|
    parser.add_argument("-v", "--verbose", action="store_true", help="be verbose")
 | 
						|
    args = parser.parse_args()
 | 
						|
 | 
						|
    if args.save and args.results and not os.path.exists(args.results):
 | 
						|
        if not os.path.exists("/tmp/topotests"):
 | 
						|
            logging.critical('No "/tmp/topotests" directory to save')
 | 
						|
            sys.exit(1)
 | 
						|
        subprocess.run(["mv", "/tmp/topotests", args.results])
 | 
						|
        # # Old location for results
 | 
						|
        # if os.path.exists("/tmp/topotests.xml", args.results):
 | 
						|
        #     subprocess.run(["mv", "/tmp/topotests.xml", args.results])
 | 
						|
 | 
						|
    assert (
 | 
						|
        args.test is None or not args.files_only
 | 
						|
    ), "Can't have both --files and --test"
 | 
						|
 | 
						|
    results = {}
 | 
						|
    ttfiles = []
 | 
						|
    if args.rundir:
 | 
						|
        basedir = os.path.realpath(args.rundir)
 | 
						|
        os.chdir(basedir)
 | 
						|
 | 
						|
        newfiles = glob.glob("tt-group-*/topotests.xml")
 | 
						|
        if newfiles:
 | 
						|
            ttfiles.extend(newfiles)
 | 
						|
        if os.path.exists("topotests.xml"):
 | 
						|
            ttfiles.append("topotests.xml")
 | 
						|
    else:
 | 
						|
        if args.results:
 | 
						|
            if os.path.exists(os.path.join(args.results, "topotests.xml")):
 | 
						|
                args.results = os.path.join(args.results, "topotests.xml")
 | 
						|
            if not os.path.exists(args.results):
 | 
						|
                logging.critical("%s doesn't exist", args.results)
 | 
						|
                sys.exit(1)
 | 
						|
            ttfiles = [args.results]
 | 
						|
        elif os.path.exists("/tmp/topotests/topotests.xml"):
 | 
						|
            ttfiles.append("/tmp/topotests/topotests.xml")
 | 
						|
 | 
						|
        if not ttfiles:
 | 
						|
            if os.path.exists("/tmp/topotests.xml"):
 | 
						|
                ttfiles.append("/tmp/topotests.xml")
 | 
						|
 | 
						|
    for f in ttfiles:
 | 
						|
        m = re.match(r"tt-group-(\d+)/topotests.xml", f)
 | 
						|
        group = int(m.group(1)) if m else 0
 | 
						|
        with open(f) as xml_file:
 | 
						|
            results[group] = xmltodict.parse(xml_file.read())["testsuites"]["testsuite"]
 | 
						|
 | 
						|
    filters = []
 | 
						|
    if "e" in args.select:
 | 
						|
        filters.append("error")
 | 
						|
    if "f" in args.select:
 | 
						|
        filters.append("failure")
 | 
						|
    if "s" in args.select:
 | 
						|
        filters.append("skipped")
 | 
						|
    if "p" in args.select:
 | 
						|
        filters.append(None)
 | 
						|
 | 
						|
    found_files = get_filtered(filters, results, args)
 | 
						|
    if found_files:
 | 
						|
        if args.test is not None:
 | 
						|
            if args.test == "all":
 | 
						|
                keys = found_files.keys()
 | 
						|
            else:
 | 
						|
                keys = [list(found_files.keys())[int(args.test)]]
 | 
						|
            for key in keys:
 | 
						|
                testcase = found_files[key]
 | 
						|
                if args.errtext:
 | 
						|
                    if "error" in testcase:
 | 
						|
                        errmsg = testcase["error"]["#text"]
 | 
						|
                    elif "failure" in testcase:
 | 
						|
                        errmsg = testcase["failure"]["#text"]
 | 
						|
                    else:
 | 
						|
                        errmsg = "none found"
 | 
						|
                    s = "{}: {}".format(key, errmsg)
 | 
						|
                elif args.time:
 | 
						|
                    text = testcase["@time"]
 | 
						|
                    s = "{}: {}".format(text, key)
 | 
						|
                elif args.errmsg:
 | 
						|
                    if "error" in testcase:
 | 
						|
                        errmsg = testcase["error"]["@message"]
 | 
						|
                    elif "failure" in testcase:
 | 
						|
                        errmsg = testcase["failure"]["@message"]
 | 
						|
                    else:
 | 
						|
                        errmsg = "none found"
 | 
						|
                    s = "{}: {}".format(key, errmsg)
 | 
						|
                else:
 | 
						|
                    s = dump_testcase(testcase)
 | 
						|
                print(s)
 | 
						|
        elif filters:
 | 
						|
            if args.enumerate:
 | 
						|
                print(
 | 
						|
                    "\n".join(["{} {}".format(i, x) for i, x in enumerate(found_files)])
 | 
						|
                )
 | 
						|
            else:
 | 
						|
                print("\n".join(found_files))
 | 
						|
 | 
						|
    if args.summary:
 | 
						|
        print_summary(results, args)
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    main()
 |