quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

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))