github.com/canonical/ubuntu-image@v0.0.0-20240430122802-2202fe98b290/tests/lib/external/snapd-testing-tools/utils/check-test-format (about) 1 #!/usr/bin/python3 2 3 """ 4 This tool is used to verify a correct format of spread tests 5 The input is a directory which is scanned recursively and all 6 the task.yaml files are check 7 """ 8 9 import argparse 10 import glob 11 import os 12 import sys 13 import yaml 14 import yamlordereddictloader 15 16 SUPPORTED_KEYS = [ 17 "summary", 18 "details", 19 "backends", 20 "systems", 21 "manual", 22 "priority", 23 "warn-timeout", 24 "kill-timeout", 25 "environment", 26 "prepare", 27 "restore", 28 "debug", 29 "execute", 30 ] 31 MANDATORY_KEYS = ["summary", "details", "execute"] 32 33 34 def check_mandatory_keys(task_keys): 35 findings = [] 36 for key in MANDATORY_KEYS: 37 if key not in task_keys: 38 findings.append("Key '{}' is mandatory".format(key)) 39 40 return findings 41 42 43 def check_keys_order(task_keys): 44 last_index = -1 45 last_key = "" 46 findings = [] 47 48 for curr_key in task_keys: 49 try: 50 curr_index = SUPPORTED_KEYS.index(curr_key) 51 if curr_index <= last_index: 52 findings.append( 53 "Keys '{}' and '{}' do not follow the desired order: {}".format( 54 last_key, curr_key, SUPPORTED_KEYS 55 ) 56 ) 57 58 last_index = curr_index 59 last_key = curr_key 60 61 except ValueError: 62 findings.append( 63 "key '{}' is not among the supported keys: {}".format( 64 curr_key, SUPPORTED_KEYS 65 ) 66 ) 67 68 return findings 69 70 71 def check_task_format(filepath): 72 if not os.path.isfile(filepath): 73 print("Format checks failed for task {}".format(filepath)) 74 print(" - The path is not a file") 75 return False 76 77 filemap = dict() 78 try: 79 with open(filepath, "r") as task: 80 filemap = yaml.load(task, Loader=yamlordereddictloader.Loader) 81 except yaml.scanner.ScannerError: 82 print("Invalid task format, checks failed for task {}".format(filepath)) 83 return False 84 85 findings = check_keys_order(filemap.keys()) 86 findings.extend(check_mandatory_keys(filemap.keys())) 87 if findings: 88 print("Format checks failed for task {}".format(filepath)) 89 for finding in findings: 90 print(" - " + finding) 91 return False 92 93 return True 94 95 def check_dir(directory): 96 if not os.path.isdir(directory): 97 print("Format checks failed for directory {}".format(directory)) 98 print(" - The path is not a directory") 99 return False 100 101 status = True 102 for file in glob.glob(os.path.join(directory, "**/task.yaml"), recursive=True): 103 if not check_task_format(file): 104 status = False 105 106 return status 107 108 def check_tests(tests): 109 status = True 110 for test in tests: 111 if not os.path.isfile(test): 112 print("Format checks failed for test {}".format(test)) 113 print(" - The path is not a file") 114 status = False 115 continue 116 117 if not check_task_format(test): 118 status = False 119 120 return status 121 122 def _make_parser(): 123 parser = argparse.ArgumentParser() 124 parser.add_argument( 125 "--dir", help="path to the directory to check recursively" 126 ) 127 parser.add_argument( 128 "--tests", help="list of tests path to check", nargs='+' 129 ) 130 return parser 131 132 133 def main(): 134 parser = _make_parser() 135 args = parser.parse_args() 136 137 status = 0 138 if args.tests: 139 if not check_tests(args.tests): 140 status = 1 141 142 if args.dir: 143 if not check_dir(args.dir): 144 status = 1 145 146 sys.exit(status) 147 148 if __name__ == "__main__": 149 main()