test_psa_compliance.py (5889B)
1 #!/usr/bin/env python3 2 """Run the PSA Crypto API compliance test suite. 3 Clone the repo and check out the commit specified by PSA_ARCH_TEST_REPO and PSA_ARCH_TEST_REF, 4 then compile and run the test suite. The clone is stored at <repository root>/psa-arch-tests. 5 Known defects in either the test suite or mbedtls / TF-PSA-Crypto - identified by their test 6 number - are ignored, while unexpected failures AND successes are reported as errors, to help 7 keep the list of known defects as up to date as possible. 8 """ 9 10 # Copyright The Mbed TLS Contributors 11 # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 12 13 import argparse 14 import os 15 import re 16 import shutil 17 import subprocess 18 import sys 19 from typing import List 20 from pathlib import Path 21 22 from mbedtls_framework import build_tree 23 24 # PSA Compliance tests we expect to fail due to known defects in Mbed TLS / 25 # TF-PSA-Crypto (or the test suite). 26 # The test numbers correspond to the numbers used by the console output of the test suite. 27 # Test number 2xx corresponds to the files in the folder 28 # psa-arch-tests/api-tests/dev_apis/crypto/test_c0xx 29 EXPECTED_FAILURES = {} # type: dict 30 31 PSA_ARCH_TESTS_REPO = 'https://github.com/ARM-software/psa-arch-tests.git' 32 PSA_ARCH_TESTS_REF = 'v23.06_API1.5_ADAC_EAC' 33 34 #pylint: disable=too-many-branches,too-many-statements,too-many-locals 35 def main(library_build_dir: str): 36 root_dir = os.getcwd() 37 install_dir = Path(library_build_dir + "/install_dir").resolve() 38 tmp_env = os.environ 39 tmp_env['CC'] = 'gcc' 40 subprocess.check_call(['cmake', '.', '-GUnix Makefiles', 41 '-B' + library_build_dir, 42 '-DCMAKE_INSTALL_PREFIX=' + str(install_dir)], 43 env=tmp_env) 44 subprocess.check_call(['cmake', '--build', library_build_dir, '--target', 'install']) 45 46 if build_tree.is_mbedtls_3_6(): 47 libraries_to_link = [str(install_dir.joinpath("lib/libmbedcrypto.a"))] 48 else: 49 libraries_to_link = [str(install_dir.joinpath("lib/" + lib)) 50 for lib in ["libtfpsacrypto.a", "libbuiltin.a", 51 "libp256m.a", "libeverest.a"]] 52 53 psa_arch_tests_dir = 'psa-arch-tests' 54 os.makedirs(psa_arch_tests_dir, exist_ok=True) 55 try: 56 os.chdir(psa_arch_tests_dir) 57 58 # Reuse existing local clone 59 subprocess.check_call(['git', 'init']) 60 subprocess.check_call(['git', 'fetch', PSA_ARCH_TESTS_REPO, PSA_ARCH_TESTS_REF]) 61 subprocess.check_call(['git', 'checkout', 'FETCH_HEAD']) 62 63 build_dir = 'api-tests/build' 64 try: 65 shutil.rmtree(build_dir) 66 except FileNotFoundError: 67 pass 68 os.mkdir(build_dir) 69 os.chdir(build_dir) 70 71 #pylint: disable=bad-continuation 72 subprocess.check_call([ 73 'cmake', '..', 74 '-GUnix Makefiles', 75 '-DTARGET=tgt_dev_apis_stdc', 76 '-DTOOLCHAIN=HOST_GCC', 77 '-DSUITE=CRYPTO', 78 '-DPSA_CRYPTO_LIB_FILENAME={}'.format(';'.join(libraries_to_link)), 79 '-DPSA_INCLUDE_PATHS=' + str(install_dir.joinpath("include")) 80 ]) 81 82 subprocess.check_call(['cmake', '--build', '.']) 83 84 proc = subprocess.Popen(['./psa-arch-tests-crypto'], 85 bufsize=1, stdout=subprocess.PIPE, universal_newlines=True) 86 87 test_re = re.compile( 88 '^TEST: (?P<test_num>[0-9]*)|' 89 '^TEST RESULT: (?P<test_result>FAILED|PASSED)' 90 ) 91 test = -1 92 unexpected_successes = set(EXPECTED_FAILURES) 93 expected_failures = [] # type: List[int] 94 unexpected_failures = [] # type: List[int] 95 if proc.stdout is None: 96 return 1 97 98 for line in proc.stdout: 99 print(line, end='') 100 match = test_re.match(line) 101 if match is not None: 102 groupdict = match.groupdict() 103 test_num = groupdict['test_num'] 104 if test_num is not None: 105 test = int(test_num) 106 elif groupdict['test_result'] == 'FAILED': 107 try: 108 unexpected_successes.remove(test) 109 expected_failures.append(test) 110 print('Expected failure, ignoring') 111 except KeyError: 112 unexpected_failures.append(test) 113 print('ERROR: Unexpected failure') 114 elif test in unexpected_successes: 115 print('ERROR: Unexpected success') 116 proc.wait() 117 118 print() 119 print('***** test_psa_compliance.py report ******') 120 print() 121 print('Expected failures:', ', '.join(str(i) for i in expected_failures)) 122 print('Unexpected failures:', ', '.join(str(i) for i in unexpected_failures)) 123 print('Unexpected successes:', ', '.join(str(i) for i in sorted(unexpected_successes))) 124 print() 125 if unexpected_successes or unexpected_failures: 126 if unexpected_successes: 127 print('Unexpected successes encountered.') 128 print('Please remove the corresponding tests from ' 129 'EXPECTED_FAILURES in tests/scripts/compliance_test.py') 130 print() 131 print('FAILED') 132 return 1 133 else: 134 print('SUCCESS') 135 return 0 136 finally: 137 os.chdir(root_dir) 138 139 if __name__ == '__main__': 140 BUILD_DIR = 'out_of_source_build' 141 142 # pylint: disable=invalid-name 143 parser = argparse.ArgumentParser() 144 parser.add_argument('--build-dir', nargs=1, 145 help='path to Mbed TLS / TF-PSA-Crypto build directory') 146 args = parser.parse_args() 147 148 if args.build_dir is not None: 149 BUILD_DIR = args.build_dir[0] 150 151 sys.exit(main(BUILD_DIR))