Merge pull request #7982 from gilles-peskine-arm/sample_program_demo_scripts-3.4
Run sample program demo scripts in all.sh
This commit is contained in:
commit
0ea1b8fe8c
6 changed files with 237 additions and 74 deletions
137
programs/demo_common.sh
Normal file
137
programs/demo_common.sh
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
## Common shell functions used by demo scripts programs/*/*.sh.
|
||||||
|
|
||||||
|
## How to write a demo script
|
||||||
|
## ==========================
|
||||||
|
##
|
||||||
|
## Include this file near the top of each demo script:
|
||||||
|
## . "${0%/*}/../demo_common.sh"
|
||||||
|
##
|
||||||
|
## Start with a "msg" call that explains the purpose of the script.
|
||||||
|
## Then call the "depends_on" function to ensure that all config
|
||||||
|
## dependencies are met.
|
||||||
|
##
|
||||||
|
## As the last thing in the script, call the cleanup function.
|
||||||
|
##
|
||||||
|
## You can use the functions and variables described below.
|
||||||
|
|
||||||
|
set -e -u
|
||||||
|
|
||||||
|
## $root_dir is the root directory of the Mbed TLS source tree.
|
||||||
|
root_dir="${0%/*}"
|
||||||
|
# Find a nice path to the root directory, avoiding unnecessary "../".
|
||||||
|
# The code supports demo scripts nested up to 4 levels deep.
|
||||||
|
# The code works no matter where the demo script is relative to the current
|
||||||
|
# directory, even if it is called with a relative path.
|
||||||
|
n=4 # limit the search depth
|
||||||
|
while ! [ -d "$root_dir/programs" ] || ! [ -d "$root_dir/library" ]; do
|
||||||
|
if [ $n -eq 0 ]; then
|
||||||
|
echo >&2 "This doesn't seem to be an Mbed TLS source tree."
|
||||||
|
exit 125
|
||||||
|
fi
|
||||||
|
n=$((n - 1))
|
||||||
|
case $root_dir in
|
||||||
|
.) root_dir="..";;
|
||||||
|
..|?*/..) root_dir="$root_dir/..";;
|
||||||
|
?*/*) root_dir="${root_dir%/*}";;
|
||||||
|
/*) root_dir="/";;
|
||||||
|
*) root_dir=".";;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
## $programs_dir is the directory containing the sample programs.
|
||||||
|
# Assume an in-tree build.
|
||||||
|
programs_dir="$root_dir/programs"
|
||||||
|
|
||||||
|
## msg LINE...
|
||||||
|
## msg <TEXT_ORIGIN
|
||||||
|
## Display an informational message.
|
||||||
|
msg () {
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
sed 's/^/# /'
|
||||||
|
else
|
||||||
|
for x in "$@"; do
|
||||||
|
echo "# $x"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
## run "Message" COMMAND ARGUMENT...
|
||||||
|
## Display the message, then run COMMAND with the specified arguments.
|
||||||
|
run () {
|
||||||
|
echo
|
||||||
|
echo "# $1"
|
||||||
|
shift
|
||||||
|
echo "+ $*"
|
||||||
|
"$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
## Like '!', but stop on failure with 'set -e'
|
||||||
|
not () {
|
||||||
|
if "$@"; then false; fi
|
||||||
|
}
|
||||||
|
|
||||||
|
## run_bad "Message" COMMAND ARGUMENT...
|
||||||
|
## Like run, but the command is expected to fail.
|
||||||
|
run_bad () {
|
||||||
|
echo
|
||||||
|
echo "$1 This must fail."
|
||||||
|
shift
|
||||||
|
echo "+ ! $*"
|
||||||
|
not "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
## config_has SYMBOL...
|
||||||
|
## Succeeds if the library configuration has all SYMBOLs set.
|
||||||
|
config_has () {
|
||||||
|
for x in "$@"; do
|
||||||
|
"$programs_dir/test/query_compile_time_config" "$x"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
## depends_on SYMBOL...
|
||||||
|
## Exit if the library configuration does not have all SYMBOLs set.
|
||||||
|
depends_on () {
|
||||||
|
m=
|
||||||
|
for x in "$@"; do
|
||||||
|
if ! config_has "$x"; then
|
||||||
|
m="$m $x"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ -n "$m" ]; then
|
||||||
|
cat >&2 <<EOF
|
||||||
|
$0: this demo requires the following
|
||||||
|
configuration options to be enabled at compile time:
|
||||||
|
$m
|
||||||
|
EOF
|
||||||
|
# Exit with a success status so that this counts as a pass for run_demos.py.
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
## Add the names of files to clean up to this whitespace-separated variable.
|
||||||
|
## The file names must not contain whitespace characters.
|
||||||
|
files_to_clean=
|
||||||
|
|
||||||
|
## Call this function at the end of each script.
|
||||||
|
## It is called automatically if the script is killed by a signal.
|
||||||
|
cleanup () {
|
||||||
|
rm -f -- $files_to_clean
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
## End of the public interfaces. Code beyond this point is not
|
||||||
|
## meant to be called directly from a demo script.
|
||||||
|
|
||||||
|
trap 'cleanup; trap - HUP; kill -HUP $$' HUP
|
||||||
|
trap 'cleanup; trap - INT; kill -INT $$' INT
|
||||||
|
trap 'cleanup; trap - TERM; kill -TERM $$' TERM
|
||||||
|
|
||||||
|
if config_has MBEDTLS_ENTROPY_NV_SEED; then
|
||||||
|
# Create a seedfile that's sufficiently long in all library configurations.
|
||||||
|
# This is necessary for programs that use randomness.
|
||||||
|
# Assume that the name of the seedfile is the default name.
|
||||||
|
files_to_clean="$files_to_clean seedfile"
|
||||||
|
dd if=/dev/urandom of=seedfile ibs=64 obs=64 count=1
|
||||||
|
fi
|
|
@ -15,36 +15,17 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
set -e -u
|
. "${0%/*}/../demo_common.sh"
|
||||||
|
|
||||||
program_name="key_ladder_demo"
|
msg <<'EOF'
|
||||||
program="${0%/*}/$program_name"
|
This script demonstrates the use of the PSA cryptography interface to
|
||||||
files_to_clean=
|
create a master key, derive a key from it and use that derived key to
|
||||||
|
wrap some data using an AEAD algorithm.
|
||||||
|
EOF
|
||||||
|
|
||||||
if [ ! -e "$program" ]; then
|
depends_on MBEDTLS_SHA256_C MBEDTLS_MD_C MBEDTLS_AES_C MBEDTLS_CCM_C MBEDTLS_PSA_CRYPTO_C MBEDTLS_FS_IO
|
||||||
# Look for programs in the current directory and the directories above it
|
|
||||||
for dir in "." ".." "../.."; do
|
|
||||||
program="$dir/programs/psa/$program_name"
|
|
||||||
if [ -e "$program" ]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ ! -e "$program" ]; then
|
|
||||||
echo "Could not find $program_name executable"
|
|
||||||
|
|
||||||
echo "If building out-of-tree, this script must be run" \
|
program="${0%/*}"/key_ladder_demo
|
||||||
"from the project build directory."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
run () {
|
|
||||||
echo
|
|
||||||
echo "# $1"
|
|
||||||
shift
|
|
||||||
echo "+ $*"
|
|
||||||
"$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ -e master.key ]; then
|
if [ -e master.key ]; then
|
||||||
echo "# Reusing the existing master.key file."
|
echo "# Reusing the existing master.key file."
|
||||||
|
@ -68,7 +49,7 @@ run "Compare the unwrapped data with the original input." \
|
||||||
cmp input.txt hello_world.txt
|
cmp input.txt hello_world.txt
|
||||||
|
|
||||||
files_to_clean="$files_to_clean hellow_orld.txt"
|
files_to_clean="$files_to_clean hellow_orld.txt"
|
||||||
! run "Derive a different key and attempt to unwrap the data. This must fail." \
|
run_bad "Derive a different key and attempt to unwrap the data." \
|
||||||
"$program" unwrap master=master.key input=hello_world.wrap output=hellow_orld.txt label=hellow label=orld
|
"$program" unwrap master=master.key input=hello_world.wrap output=hellow_orld.txt label=hellow label=orld
|
||||||
|
|
||||||
files_to_clean="$files_to_clean hello.key"
|
files_to_clean="$files_to_clean hello.key"
|
||||||
|
@ -79,5 +60,4 @@ run "Check that we get the same key by unwrapping data made by the other key." \
|
||||||
"$program" unwrap master=hello.key label=world \
|
"$program" unwrap master=hello.key label=world \
|
||||||
input=hello_world.wrap output=hello_world.txt
|
input=hello_world.wrap output=hello_world.txt
|
||||||
|
|
||||||
# Cleanup
|
cleanup
|
||||||
rm -f $files_to_clean
|
|
||||||
|
|
|
@ -18,34 +18,21 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
set -e -u
|
. "${0%/*}/../demo_common.sh"
|
||||||
|
|
||||||
program_name="dlopen"
|
msg "Test the dynamic loading of libmbed*"
|
||||||
program_dir="${0%/*}"
|
|
||||||
program="$program_dir/$program_name"
|
|
||||||
|
|
||||||
|
program="$programs_dir/test/dlopen"
|
||||||
|
library_dir="$root_dir/library"
|
||||||
|
|
||||||
|
# Skip this test if we don't have a shared library build. Detect this
|
||||||
|
# through the absence of the demo program.
|
||||||
if [ ! -e "$program" ]; then
|
if [ ! -e "$program" ]; then
|
||||||
# Look for programs in the current directory and the directories above it
|
msg "$0: this demo requires a shared library build."
|
||||||
for dir in "." ".." "../.."; do
|
# Exit with a success status so that this counts as a pass for run_demos.py.
|
||||||
program_dir="$dir/programs/test"
|
exit
|
||||||
program="$program_dir/$program_name"
|
|
||||||
if [ -e "$program" ]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ ! -e "$program" ]; then
|
|
||||||
echo "Could not find $program_name program"
|
|
||||||
|
|
||||||
echo "Make sure that Mbed TLS is built as a shared library." \
|
|
||||||
"If building out-of-tree, this script must be run" \
|
|
||||||
"from the project build directory."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
top_dir="$program_dir/../.."
|
|
||||||
library_dir="$top_dir/library"
|
|
||||||
|
|
||||||
# ELF-based Unix-like (Linux, *BSD, Solaris, ...)
|
# ELF-based Unix-like (Linux, *BSD, Solaris, ...)
|
||||||
if [ -n "${LD_LIBRARY_PATH-}" ]; then
|
if [ -n "${LD_LIBRARY_PATH-}" ]; then
|
||||||
LD_LIBRARY_PATH="$library_dir:$LD_LIBRARY_PATH"
|
LD_LIBRARY_PATH="$library_dir:$LD_LIBRARY_PATH"
|
||||||
|
@ -62,6 +49,6 @@ else
|
||||||
fi
|
fi
|
||||||
export DYLD_LIBRARY_PATH
|
export DYLD_LIBRARY_PATH
|
||||||
|
|
||||||
echo "Running dynamic loading test program: $program"
|
msg "Running dynamic loading test program: $program"
|
||||||
echo "Loading libraries from: $library_dir"
|
msg "Loading libraries from: $library_dir"
|
||||||
"$program"
|
"$program"
|
||||||
|
|
|
@ -1063,6 +1063,9 @@ component_test_default_out_of_box () {
|
||||||
|
|
||||||
msg "selftest: make, default config (out-of-box)" # ~10s
|
msg "selftest: make, default config (out-of-box)" # ~10s
|
||||||
programs/test/selftest
|
programs/test/selftest
|
||||||
|
|
||||||
|
msg "program demos: make, default config (out-of-box)" # ~10s
|
||||||
|
tests/scripts/run_demos.py
|
||||||
}
|
}
|
||||||
|
|
||||||
component_test_default_cmake_gcc_asan () {
|
component_test_default_cmake_gcc_asan () {
|
||||||
|
@ -1073,6 +1076,9 @@ component_test_default_cmake_gcc_asan () {
|
||||||
msg "test: main suites (inc. selftests) (ASan build)" # ~ 50s
|
msg "test: main suites (inc. selftests) (ASan build)" # ~ 50s
|
||||||
make test
|
make test
|
||||||
|
|
||||||
|
msg "program demos (ASan build)" # ~10s
|
||||||
|
tests/scripts/run_demos.py
|
||||||
|
|
||||||
msg "test: selftest (ASan build)" # ~ 10s
|
msg "test: selftest (ASan build)" # ~ 10s
|
||||||
programs/test/selftest
|
programs/test/selftest
|
||||||
|
|
||||||
|
@ -1862,6 +1868,9 @@ component_test_full_cmake_clang () {
|
||||||
msg "test: cpp_dummy_build (full config, clang)" # ~ 1s
|
msg "test: cpp_dummy_build (full config, clang)" # ~ 1s
|
||||||
programs/test/cpp_dummy_build
|
programs/test/cpp_dummy_build
|
||||||
|
|
||||||
|
msg "program demos (full config, clang)" # ~10s
|
||||||
|
tests/scripts/run_demos.py
|
||||||
|
|
||||||
msg "test: psa_constant_names (full config, clang)" # ~ 1s
|
msg "test: psa_constant_names (full config, clang)" # ~ 1s
|
||||||
tests/scripts/test_psa_constant_names.py
|
tests/scripts/test_psa_constant_names.py
|
||||||
|
|
||||||
|
@ -2045,6 +2054,9 @@ component_test_full_deprecated_warning () {
|
||||||
|
|
||||||
msg "test: full config + MBEDTLS_TEST_DEPRECATED" # ~ 30s
|
msg "test: full config + MBEDTLS_TEST_DEPRECATED" # ~ 30s
|
||||||
make test
|
make test
|
||||||
|
|
||||||
|
msg "program demos: full config + MBEDTLS_TEST_DEPRECATED" # ~10s
|
||||||
|
tests/scripts/run_demos.py
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check that the specified libraries exist and are empty.
|
# Check that the specified libraries exist and are empty.
|
||||||
|
@ -5192,6 +5204,9 @@ component_test_memsan () {
|
||||||
msg "test: main suites (MSan)" # ~ 10s
|
msg "test: main suites (MSan)" # ~ 10s
|
||||||
make test
|
make test
|
||||||
|
|
||||||
|
msg "program demos (MSan)" # ~20s
|
||||||
|
tests/scripts/run_demos.py
|
||||||
|
|
||||||
msg "test: ssl-opt.sh (MSan)" # ~ 1 min
|
msg "test: ssl-opt.sh (MSan)" # ~ 1 min
|
||||||
tests/ssl-opt.sh
|
tests/ssl-opt.sh
|
||||||
|
|
||||||
|
|
|
@ -162,24 +162,6 @@ def is_windows_file(filepath):
|
||||||
return ext in ('.bat', '.dsp', '.dsw', '.sln', '.vcxproj')
|
return ext in ('.bat', '.dsp', '.dsw', '.sln', '.vcxproj')
|
||||||
|
|
||||||
|
|
||||||
class PermissionIssueTracker(FileIssueTracker):
|
|
||||||
"""Track files with bad permissions.
|
|
||||||
|
|
||||||
Files that are not executable scripts must not be executable."""
|
|
||||||
|
|
||||||
heading = "Incorrect permissions:"
|
|
||||||
|
|
||||||
# .py files can be either full scripts or modules, so they may or may
|
|
||||||
# not be executable.
|
|
||||||
suffix_exemptions = frozenset({".py"})
|
|
||||||
|
|
||||||
def check_file_for_issue(self, filepath):
|
|
||||||
is_executable = os.access(filepath, os.X_OK)
|
|
||||||
should_be_executable = filepath.endswith((".sh", ".pl"))
|
|
||||||
if is_executable != should_be_executable:
|
|
||||||
self.files_with_issues[filepath] = None
|
|
||||||
|
|
||||||
|
|
||||||
class ShebangIssueTracker(FileIssueTracker):
|
class ShebangIssueTracker(FileIssueTracker):
|
||||||
"""Track files with a bad, missing or extraneous shebang line.
|
"""Track files with a bad, missing or extraneous shebang line.
|
||||||
|
|
||||||
|
@ -386,7 +368,6 @@ class IntegrityChecker:
|
||||||
self.logger = None
|
self.logger = None
|
||||||
self.setup_logger(log_file)
|
self.setup_logger(log_file)
|
||||||
self.issues_to_check = [
|
self.issues_to_check = [
|
||||||
PermissionIssueTracker(),
|
|
||||||
ShebangIssueTracker(),
|
ShebangIssueTracker(),
|
||||||
EndOfFileNewlineIssueTracker(),
|
EndOfFileNewlineIssueTracker(),
|
||||||
Utf8BomIssueTracker(),
|
Utf8BomIssueTracker(),
|
||||||
|
|
63
tests/scripts/run_demos.py
Executable file
63
tests/scripts/run_demos.py
Executable file
|
@ -0,0 +1,63 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Run the Mbed TLS demo scripts.
|
||||||
|
"""
|
||||||
|
import argparse
|
||||||
|
import glob
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def run_demo(demo, quiet=False):
|
||||||
|
"""Run the specified demo script. Return True if it succeeds."""
|
||||||
|
args = {}
|
||||||
|
if quiet:
|
||||||
|
args['stdout'] = subprocess.DEVNULL
|
||||||
|
args['stderr'] = subprocess.DEVNULL
|
||||||
|
returncode = subprocess.call([demo], **args)
|
||||||
|
return returncode == 0
|
||||||
|
|
||||||
|
def run_demos(demos, quiet=False):
|
||||||
|
"""Run the specified demos and print summary information about failures.
|
||||||
|
|
||||||
|
Return True if all demos passed and False if a demo fails.
|
||||||
|
"""
|
||||||
|
failures = []
|
||||||
|
for demo in demos:
|
||||||
|
if not quiet:
|
||||||
|
print('#### {} ####'.format(demo))
|
||||||
|
success = run_demo(demo, quiet=quiet)
|
||||||
|
if not success:
|
||||||
|
failures.append(demo)
|
||||||
|
if not quiet:
|
||||||
|
print('{}: FAIL'.format(demo))
|
||||||
|
if quiet:
|
||||||
|
print('{}: {}'.format(demo, 'PASS' if success else 'FAIL'))
|
||||||
|
else:
|
||||||
|
print('')
|
||||||
|
successes = len(demos) - len(failures)
|
||||||
|
print('{}/{} demos passed'.format(successes, len(demos)))
|
||||||
|
if failures and not quiet:
|
||||||
|
print('Failures:', *failures)
|
||||||
|
return not failures
|
||||||
|
|
||||||
|
def run_all_demos(quiet=False):
|
||||||
|
"""Run all the available demos.
|
||||||
|
|
||||||
|
Return True if all demos passed and False if a demo fails.
|
||||||
|
"""
|
||||||
|
all_demos = glob.glob('programs/*/*_demo.sh')
|
||||||
|
if not all_demos:
|
||||||
|
# Keep the message on one line. pylint: disable=line-too-long
|
||||||
|
raise Exception('No demos found. run_demos needs to operate from the Mbed TLS toplevel directory.')
|
||||||
|
return run_demos(all_demos, quiet=quiet)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument('--quiet', '-q',
|
||||||
|
action='store_true',
|
||||||
|
help="suppress the output of demos")
|
||||||
|
options = parser.parse_args()
|
||||||
|
success = run_all_demos(quiet=options.quiet)
|
||||||
|
sys.exit(0 if success else 1)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
Loading…
Reference in a new issue