tests area added, perftest wrapper and perf tests handshakes per second added
authoralich <alich@openssl.org>
Wed, 7 Jun 2023 13:55:02 +0000 (15:55 +0200)
committerMatt Caswell <matt@openssl.org>
Wed, 5 Jul 2023 12:46:52 +0000 (13:46 +0100)
Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/tools/pull/19)

tests/README.md [new file with mode: 0644]
tests/build/build.sh [new file with mode: 0755]
tests/install.sh [new file with mode: 0755]
tests/perftest/handshakes_per_second/handshakes_per_second.sh [new file with mode: 0755]
tests/perftest/perftest_wrapper.sh [new file with mode: 0755]

diff --git a/tests/README.md b/tests/README.md
new file mode 100644 (file)
index 0000000..67562a5
--- /dev/null
@@ -0,0 +1,13 @@
+# Tests
+
+This area contains bunch extended of tests like performance.
+
+- install.sh ................................................ script for installing tests and helpers into /opt/openssl
+
+- build/build.sh ............................................ OpenSSL build test, run with -h for more info
+
+- perftest/ ................................................. Performance tests area
+
+- perftest/perftest_wrapper.sh .............................. Performance test wrapper for Zabbix, run with -h for more info
+
+- perftest/handshakes_per_second/handshakes_per_second.sh ... Handshakes per second performance test, run with -h for more info
diff --git a/tests/build/build.sh b/tests/build/build.sh
new file mode 100755 (executable)
index 0000000..fc365ec
--- /dev/null
@@ -0,0 +1,148 @@
+#!/bin/bash
+
+WORK_DIR=/opt/openssl/tests/build
+REPO_DIR=${WORK_DIR}/openssl
+TOOLSREPO_DIR=""
+FLAG_FILE=${WORK_DIR}/RUNNING
+[ -f ${FLAG_FILE} ] && echo "The build task is already running. Quitting." && exit 1 
+# default metrics values
+ALLOWED_OSSL_VERSIONS=("master" "1.1.1" "3.0" "3.1")
+OSSL_BASE_GIT_LINK="https://github.com/openssl"
+OSSL_GIT_LINK="${OSSL_BASE_GIT_LINK}/openssl"
+OSSLTOOLS_GIT_LINK="${OSSL_BASE_GIT_LINK}/tools"
+TOOLS=0
+declare -A OSSL_GIT_VERSIONS
+OSSL_GIT_VERSIONS[master]="master"
+OSSL_GIT_VERSIONS[1.1.1]="OpenSSL_1_1_1-stable"
+OSSL_GIT_VERSIONS[3.0]="openssl-3.0"
+OSSL_GIT_VERSIONS[3.1]="openssl-3.1"
+OSSL_VERSION=""
+
+# print help
+function print_help() {
+    echo "Usage: ${0} [options]"
+    echo "    options:"
+    echo "        -h ....................... this help"
+    echo "        -t ....................... build Tools as well"
+    echo "        -V <OpenSSL version> ..... OpenSSL version to build"
+    MAXLEN=0
+    for i in ${ALLOWED_OSSL_VERSIONS[@]}; do [ ${#i} -gt ${MAXLEN} ] && MAXLEN=${#i}; done
+    for value in ${ALLOWED_OSSL_VERSIONS[@]}; do
+        echo -n "            ${value} ......"
+        for i in $(seq 1 1 $(expr ${MAXLEN} - ${#value})); do echo -n "."; done
+        [ "${value}" == "${ALLOWED_OSSL_VERSIONS[0]}" ] && \
+            echo " openssl-${value} (DEFAULT)" || \
+            echo " openssl-${value}"
+    done
+}
+
+# arguments parser
+function parse_args() {
+    while getopts 'htV:' option; do
+    case "${option}" in
+        # help
+        h)
+            print_help
+            exit 0
+            ;;
+        # Tools
+        t)
+            TOOLSREPO_DIR="${WORK_DIR}/tools"
+            ;;
+        # OpenSSL version
+        V)
+            # used parameter but no version given
+            if [ -z "${OPTARG}" ] || $(echo "${OPTARG}" | grep -q "^-"); then
+                print_help
+                exit 1
+            fi
+            # allowed values
+            for value in ${ALLOWED_OSSL_VERSIONS[@]}; do
+                [ "${value}" == "${OPTARG}" ] && OSSL_VERSION=${OPTARG} && break
+            done
+            [ "${OSSL_VERSION}" != "${OPTARG}" ] && print_help && exit 1
+            ;;
+        *)
+            print_help
+            exit 1
+            ;;
+    esac
+    done
+}
+
+# cleanup
+function cleanup() {
+    [ -f ${FLAG_FILE} ] && rm ${FLAG_FILE}
+}
+
+
+# SETUP
+echo "*************** Setup ***************"
+# arguments
+parse_args "$@"
+# preparation and pulling code from the repository
+echo "Prepairing fresh bits from GIT in Working directory. This may take a while..."
+[ ! -d ${WORK_DIR} ] && mkdir -p ${WORK_DIR}
+cd ${WORK_DIR} && touch ${FLAG_FILE} || { echo "Cannot access working directory: ${WORK_DIR}"; cleanup; exit 1; }
+# clone OpenSSL repository
+if [ ! -d ${REPO_DIR} ]; then
+    git clone ${OSSL_GIT_LINK} ${REPO_DIR} >/dev/null 2>&1 || { echo "Cannot clone openssl repository. Quitting."; cleanup; exit 1; }
+else
+    cd ${REPO_DIR}
+    git reset --hard >/dev/null 2>&1
+    git clean -fxd >/dev/null 2>&1
+    git pull >/dev/null 2>&1
+    cd ${WORK_DIR}
+fi
+# clone Tools as well
+if [ -n "${TOOLSREPO_DIR}" ]; then
+    if [ ! -d ${TOOLSREPO_DIR} ]; then
+        git clone ${OSSLTOOLS_GIT_LINK} ${TOOLSREPO_DIR} >/dev/null 2>&1 || { echo "Cannot clone openssl tools repository. Quitting."; cleanup; exit 1; }
+    else
+        cd ${TOOLSREPO_DIR}
+        git reset --hard >/dev/null 2>&1
+        git clean -fxd >/dev/null 2>&1
+        git pull >/dev/null 2>&1
+        cd ${WORK_DIR}
+    fi
+fi
+
+# TEST
+# determine whether to build all versions or there is a given one
+[ -n "${OSSL_VERSION}" ] && ALLOWED_OSSL_VERSIONS=(${OSSL_VERSION})
+for osslversion in ${ALLOWED_OSSL_VERSIONS[@]}; do
+    # OpenSSL
+    #   repo direcotry
+    if [ ! -d ${WORK_DIR}/${osslversion} ]; then
+        cp -r ${REPO_DIR} ${WORK_DIR}/${osslversion}
+        cd ${WORK_DIR}/${osslversion}
+        git checkout ${OSSL_GIT_VERSIONS[${osslversion}]}
+    else
+        cd ${WORK_DIR}/${osslversion}
+        git checkout ${OSSL_GIT_VERSIONS[${osslversion}]}
+        git reset --hard >/dev/null 2>&1
+        git clean -fxd >/dev/null 2>&1
+        git pull >/dev/null 2>&1
+    fi
+    #   BUILD
+    #./Configure --prefix=/usr/local/ssl --openssldir=/usr/local/ssl -Wl,--enable-new-dtags,-rpath,$(LIBRPATH) && make
+    ./config && make || { echo "Build failed. Quitting."; cleanup; exit 1; }
+    # Tools
+    #   repo direcotry
+    if [ -n "${TOOLSREPO_DIR}" ]; then
+        TOOLSREPO_VER_DIR=${WORK_DIR}/${osslversion}-tools
+        # cleanup
+        [ -d ${TOOLSREPO_VER_DIR} ] && rm -rf ${TOOLSREPO_VER_DIR}
+        cp -r ${TOOLSREPO_DIR} ${TOOLSREPO_VER_DIR}
+        #   BUILD
+        cd ${TOOLSREPO_VER_DIR}/perf
+        export TARGET_OSSL_INCLUDE_PATH=${WORK_DIR}/${osslversion}/include
+        export TARGET_OSSL_LIBRARY_PATH=${WORK_DIR}/${osslversion}
+        make || { echo "Build failed. Quitting."; cleanup; exit 1; }
+    fi
+    cd ${WORK_DIR}
+done
+
+echo "Finished successfuly."
+cleanup
+exit 0
diff --git a/tests/install.sh b/tests/install.sh
new file mode 100755 (executable)
index 0000000..e82713b
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/bash
+echo "Creating working directory in /opt/openssl/tests and copying necesary files."
+mkdir -p /opt/openssl/tests && cp -r build perftest /opt/openssl/tests
+[ $? -eq 0 ] && { echo "PASSED"; exit 0; } || { echo "FAILED"; exit 1; }
diff --git a/tests/perftest/handshakes_per_second/handshakes_per_second.sh b/tests/perftest/handshakes_per_second/handshakes_per_second.sh
new file mode 100755 (executable)
index 0000000..2878703
--- /dev/null
@@ -0,0 +1,181 @@
+#!/bin/bash
+
+PERFTEST_WRAPPER=/opt/openssl/tests/perftest/perftest_wrapper.sh
+BUILDS_DIR=/opt/openssl/tests/build
+# default metrics values
+ALLOWED_OSSL_VERSIONS=("master" "1.1.1" "3.0" "3.1")
+OSSL_GIT_BASE_LINK="https://github.com/openssl"
+OSSL_REPOS=("openssl" "tools")
+declare -A OSSL_GIT_BRANCHES
+OSSL_GIT_BRANCHES[master]="master"
+OSSL_GIT_BRANCHES[1.1.1]="OpenSSL_1_1_1-stable"
+OSSL_GIT_BRANCHES[3.0]="openssl-3.0"
+OSSL_GIT_BRANCHES[3.1]="openssl-3.1"
+OSSL_VERSION=${ALLOWED_OSSL_VERSIONS[0]}
+ALLOWED_THREADS=(0 1 10 100 500 1000)
+ZABBIX_SERVER=127.0.0.1
+THREADS=1
+REPEAT=1
+# PerfTest-OpenSSL-<openssl-branch>
+METRIC_HOST=""
+# perftest.handshakes-per-second-<threads>"
+METRIC_TITLE=""
+DATA=()
+DRY_RUN=0
+VERBOSITY=0
+OPTS=""
+
+
+# print help
+function print_help() {
+    echo "Usage: ${0} [options]"
+    echo "    options:"
+    echo "        -d ...... dry run, don't send results anywhere"
+    echo "        -h ...... this help"
+    echo "        -r <repeat test N times>"
+    echo "        -t <number of threads>"
+    MAXLEN=0
+    for i in ${ALLOWED_THREADS[@]}; do [ ${#i} -gt ${MAXLEN} ] && MAXLEN=${#i}; done
+    for value in ${ALLOWED_THREADS[@]}; do
+        for i in $(seq 1 1 $(expr ${MAXLEN} - ${#value})); do echo -n " "; done
+        [ ${value} -eq 0 ] && \
+            echo "             0 (multiple runs with all the allowed values)" && continue
+        [ ${value} -eq 1 ] && \
+            echo "             ${value} (DEFAULT)" || \
+            echo "             ${value}"
+    done
+    echo "        -V <OpenSSL version> to run on"
+    MAXLEN=0
+    for i in ${ALLOWED_OSSL_VERSIONS[@]}; do [ ${#i} -gt ${MAXLEN} ] && MAXLEN=${#i}; done
+    for value in ${ALLOWED_OSSL_VERSIONS[@]}; do
+        echo -n "            ${value} ......"
+        for i in $(seq 1 1 $(expr ${MAXLEN} - ${#value})); do echo -n "."; done
+        [ "${value}" == "${ALLOWED_OSSL_VERSIONS[0]}" ] && \
+            echo " openssl-${value} (DEFAULT)" || \
+            echo " openssl-${value}"
+    done
+    echo "        -v ...... verbosity"
+    echo "        -z <Zabbix server IP address / hostname>"
+    echo
+    echo "Dependencies:"
+    echo "    OpenSSL and OpenSSL-tools built in ../build/<version> and ../build/<version>-tools"
+}
+
+# arguments parser
+function parse_args() {
+    while getopts 'dhr:t:V:vz:' option; do
+    case "${option}" in
+        # dry run
+        d)
+            DRY_RUN=1
+            OPTS+=" -d"
+            ;;
+        # help
+        h)
+            print_help
+            exit 0
+            ;;
+        # repeat
+        r)
+            # used parameter but no or wrong value given
+            if [ -z "${OPTARG}" ] || $(echo "${OPTARG}" | grep -q "^-") || [[ ${OPTARG} != ?(-)+([0-9]) ]] || [ ${OPTARG} -le 0 ]; then
+                print_help
+                exit 1
+            fi
+            REPEAT=${OPTARG}
+            ;;
+        # thread count
+        t)
+            # used parameter but no or wrong value given
+            if [ -z "${OPTARG}" ] || $(echo "${OPTARG}" | grep -q "^-") || [[ ${OPTARG} != ?(-)+([0-9]) ]]; then
+                print_help
+                exit 1
+            fi
+            # threads count check - available options in $ALLOWED_THREADS
+            for value in ${ALLOWED_THREADS[@]}; do
+                [ ${value} -eq ${OPTARG} ] && THREADS=${OPTARG} && break
+            done
+            # 0 ... run with all the defined thread values
+            [ ${THREADS} -ne ${OPTARG} ] && print_help && exit 1
+            ;;
+        # OpenSSL version
+        V)
+            # used parameter but no version given
+            if [ -z "${OPTARG}" ] || $(echo "${OPTARG}" | grep -q "^-"); then
+                print_help
+                exit 1
+            fi
+            # allowed values
+            for value in ${ALLOWED_OSSL_VERSIONS[@]}; do
+                [ "${value}" == "${OPTARG}" ] && OSSL_VERSION=${OPTARG} && break
+            done
+            [ "${OSSL_VERSION}" != "${OPTARG}" ] && print_help && exit 1
+            ;;
+        # verbosity
+        v)
+            VERBOSITY=1
+            OPTS+=" -v"
+            ;;
+        z)
+            if [ -z "${OPTARG}" ]; then
+                print_help
+                exit 1
+            fi
+            ZABBIX_SERVER=${OPTARG}
+            ;;
+
+        *)
+            print_help
+            exit 1
+            ;;
+    esac
+    done
+}
+
+
+# return median from array of $DATA
+function median() {
+    MID_INDEX=$(expr ${REPEAT} / 2)
+    TMP_DATA=($(printf '%s\n' "${DATA[@]}" | sort))
+    echo ${TMP_DATA[${MID_INDEX}]}
+}
+
+
+# SETUP
+echo "*************** Setup ***************"
+[ ! -x ${PERFTEST_WRAPPER} ] && echo "Error: ${PERFTEST_WRAPPER} not executble or doesn't exist. Quitting..." && exit 1
+# arguments
+parse_args "$@"
+# builds check
+[ ! -x ${BUILDS_DIR}/${OSSL_VERSION}-tools/perf/handshake ] && echo "Error: The handshake test for OpenSSL ${OSSL_VERSION} not available. Quitting." && exit 1
+# metrics setup
+METRIC_HOST="PerfTest-OpenSSL-${OSSL_VERSION}"
+METRIC_TITLE="perftest.handshakes-per-second-${THREADS}"
+
+# TEST
+echo "*************** Tests ***************"
+# test execution via "perftest wrapper"
+# only 1 test -> redefining the array
+[ ${THREADS} -ne 0 ] && ALLOWED_THREADS=(${THREADS})
+for value in ${ALLOWED_THREADS[@]}; do
+    echo "----"
+    echo "Running test '${METRIC_TITLE}'"
+    THREADS=${value}
+    METRIC_TITLE="perftest.handshakes-per-second-${THREADS}"
+    DATA=()
+    for i in $(seq 1 1 ${REPEAT}); do
+        CMD2RUN="LD_LIBRARY_PATH=${BUILDS_DIR}/${OSSL_VERSION} ${BUILDS_DIR}/${OSSL_VERSION}-tools/perf/handshake ${BUILDS_DIR}/${OSSL_VERSION}/test/certs ${THREADS} | grep 'Handshakes per second' | awk '{ print \$4; }'"
+        if [ ${VERBOSITY} -ne 0 ]; then
+            echo "Running: ${CMD2RUN}"
+            DATA+=($(eval "${CMD2RUN}"))
+            echo "    Rusult: ${DATA[$((${#DATA[@]} - 1))]}"
+            echo 
+        else
+            DATA+=($(eval ${CMD2RUN}))
+        fi
+    done
+    # "dry run" and "verbosity" are passed to perftest_wrapper as well
+    ${PERFTEST_WRAPPER} -z ${ZABBIX_SERVER} -g "${METRIC_HOST}" -m "${METRIC_TITLE}" -c "echo $(median)" ${OPTS}
+done
+
+exit 0
diff --git a/tests/perftest/perftest_wrapper.sh b/tests/perftest/perftest_wrapper.sh
new file mode 100755 (executable)
index 0000000..02a9470
--- /dev/null
@@ -0,0 +1,163 @@
+#!/bin/bash
+
+ZABBIX_SERVER=127.0.0.1
+TIMESTAMP=$(date +%s)
+DRY_RUN=0
+VERBOSITY=0
+CMD=""
+GROUP_TITLE="Performance tests"
+METRIC_TITLE=""
+METRIC_VALUE=
+
+# print help
+function print_help() {
+    echo "Usage: ${0} [options]"
+    echo "    options:"
+    echo "        -c <a command produces a number>"
+    echo "        -d ... dry run"
+    echo "                ... executes command but results are printed insted of sent to servers"
+    echo "        -g <group of metrics title>"
+    echo "                ... this is defined as a 'host' in Zabbix server, default value set to 'Performance tests'"
+    echo "        -h ... print this help"
+    echo "        -m <metric title>"
+    echo "                ... this is defined as an 'item' in Zabbix server"
+    echo "        -v ... set verbosity"
+    echo "        -z <Zabbix server IP address / hostname>"
+    echo
+    echo "Dependencies:"
+    echo "    zabbix_sender"
+}
+
+# arguments parser
+function parse_args() {
+    [ $# -eq 0 ] && print_help && exit 1
+    while getopts 'c:dg:hm:vz:' option; do
+    case "${option}" in
+        # command
+        c)
+            # wrapped command
+            if [ -z "${OPTARG}" ]; then
+                print_help
+                exit 1
+            fi
+            CMD=${OPTARG}
+            ;;
+        # dry run
+        d)
+            DRY_RUN=1
+            ;;
+        # group of metrics title (or "host" in Zabbix server)
+        #  it must follow the name of "host" in Zabbix server, for example: "Performance tests"
+        g)
+            if [ -z "${OPTARG}" ]; then
+                print_help
+                exit 1
+            fi
+            GROUP_TITLE=${OPTARG}
+            ;;
+        # help
+        h)
+            print_help
+            exit 0
+            ;;
+        # metric title
+        #   it must follow the name defined in Zabbix item, for example: "perftest.openssl-master.build_time"
+        m)
+            if [ -z "${OPTARG}" ]; then
+                print_help
+                exit 1
+            fi
+            METRIC_TITLE=${OPTARG}
+            ;;
+        # verbosity
+        v)
+            VERBOSITY=1
+            ;;
+        z)
+            if [ -z "${OPTARG}" ]; then
+                print_help
+                exit 1
+            fi
+            ZABBIX_SERVER=${OPTARG}
+            ;;
+        *)
+            print_help
+            exit 1
+            ;;
+    esac
+    done
+}
+
+# test of variables
+function test_vars() {
+    local err=0
+    # command
+    if [ -z "${CMD}" ]; then
+        echo "Error: 'command' to run is not set"
+        err=1
+    fi
+    # metrics "host"
+    if [ -z "${GROUP_TITLE}" ]; then
+        echo "Error: 'group title' is not set"
+        err=1
+    fi
+    # metric
+    if [ -z "${METRIC_TITLE}" ]; then
+        echo "Error: 'metric title' is not set"
+        err=1
+    fi
+    # zabbix server connection
+    which zabbix_sender 2>&1 >/dev/null && {
+        zabbix_sender -z ${ZABBIX_SERVER} -s "this_connection_test_host" -k "connection_test_key" -o 1 | grep -q 'sent: 1;'
+        if [ $? -ne 0 ]; then
+            echo "Error: Zabbix server is not accessible."
+            err=1
+        fi
+    } ||
+    { echo "Error: zabbix_sender must be installed."; err=1; }
+    [ ${err} -ne 0 ] && exit 1
+}
+
+
+# ****** START ******
+# arguments
+parse_args "$@"
+# verbosity
+if [ ${VERBOSITY} -ne 0 ]; then
+    echo "****** Variables ******"
+    echo "DRY_RUN        = ${DRY_RUN}"
+    echo "VERBOSITY      = ${VERBOSITY}"
+    echo "GROUP_TITLE    = ${GROUP_TITLE}"
+    echo "METRIC_TITLE   = ${METRIC_TITLE}"
+    echo "ZABBIX_SERVER  = ${ZABBIX_SERVER}"
+    echo "CMD            = ${CMD}"
+    echo "***********************"
+    echo
+fi
+# set variables
+test_vars
+
+# cmd execution
+METRIC_VALUE=$(eval "${CMD}")
+# check
+[ -z "${METRIC_VALUE}" ] && echo "Error: empty metric, nothing to report. Quitting..." && exit 1 
+
+CMD2RUN="zabbix_sender -z ${ZABBIX_SERVER} -s '${GROUP_TITLE}' -k '${METRIC_TITLE}' -o ${METRIC_VALUE} >/dev/null"
+# verbosity
+if [ ${VERBOSITY} -ne 0 ]; then
+    echo "****** Data collection commands ******"
+    echo "METRIC_VALUE = ${METRIC_VALUE}"
+    echo "zabbix_sender ${CMD2RUN}"
+    echo "**************************************"
+    echo
+fi
+if [ ${DRY_RUN} -eq 0 ]; then
+    # sending data to Zabbix server
+    eval ${CMD2RUN}
+    [ $? -eq 0 ] && echo "[Zabbix] '${METRIC_TITLE}'->${METRIC_VALUE} .... PASSED" || echo "[Zabbix] '${METRIC_TITLE}'->${METRIC_VALUE} .... FAILED"
+else
+    echo "Dry run, data are not sent to Zabbix server."
+    echo "[Test] '${METRIC_TITLE}'->${METRIC_VALUE}"
+fi
+
+exit 0