#!/bin/sh -eu # Process inputs DD_DOMAIN="${1:-}" tc="${2:-}" duration="${3:-60}" USE_SELENIUM="${USE_SELENIUM:-YES}" SCRIPT_PATH="$(realpath "${0}")" SCRIPT_NAME="$(basename "${0}")" JMETER_DEFAULT="./apache-jmeter-5.5/bin/jmeter" full_tests() { # Runtime: 7 tests * 5 mins / test = 35 mins # Cool-off periods: 30s * 6 = 3 mins # Total: 38 mins cooloff="30" "${SCRIPT_PATH}" "${DD_DOMAIN}" 10 300 sleep "${cooloff}" "${SCRIPT_PATH}" "${DD_DOMAIN}" 20 300 sleep "${cooloff}" "${SCRIPT_PATH}" "${DD_DOMAIN}" 30 300 sleep "${cooloff}" "${SCRIPT_PATH}" "${DD_DOMAIN}" 60 300 sleep "${cooloff}" "${SCRIPT_PATH}" "${DD_DOMAIN}" 100 300 sleep "${cooloff}" "${SCRIPT_PATH}" "${DD_DOMAIN}" 300 300 sleep "${cooloff}" "${SCRIPT_PATH}" "${DD_DOMAIN}" 600 300 } help_users_file() { cat <<-EOF The format of the users.csv file must be: USERNAME1,PASSWORD1 USERNAME2,PASSWORD2 ... Take care not to have any spaces between fields. EOF } help_jmeter() { cat <<-EOF Note this scripts depends on JMeter with some plugins enabled. You can set the JMETER environment variable to its binary path. If this variable is unset, ${JMETER_DEFAULT} will be used, from this script's location. See: https://jmeter.apache.org/download_jmeter.cgi https://jmeter-plugins.org/install/Install/ EOF } help() { cat <<-EOF Examples: ./${SCRIPT_NAME} DD_DOMAIN THREAD_COUNT [DURATION] or: ./${SCRIPT_NAME} --full-tests DD_DOMAIN EOF help_jmeter cat <<-EOF When using --full-tests, a pre-selected combination of THREAD_COUNT and DURATION will be used against DD_DOMAIN. Where DD_DOMAIN is the base domain, e.g. if your DD instance's Nextcloud can be accessed at nextcloud.example.org, the parameter should be "example.org". THREAD_COUNT refers to the amount of users that will be simulated. DURATION is the total test time time in seconds. Defaults to 60. Note that you MUST have a users.csv file in the current directory. By default this script runs tests with selenium and documents the session as would be perceived by a user. You can disable this behaviour by setting the environment variable USE_SELENIUM=NO. EOF help_users_file } if [ "${DD_DOMAIN:-}" = "--full-tests" ]; then shift # Consume operation argument # Re-set global variable DD_DOMAIN="${1:-}" # Execute full suite full_tests # And exit exit 0 elif [ "${1:-}" = "--help" ]; then help exit 0 elif [ -z "${DD_DOMAIN:-}" ] || [ -z "${tc:-}" ]; then help >> /dev/stderr exit 1 fi USERS_FILE="$(pwd)/users.csv" DOCS_FILE="$(pwd)/docs.csv" # Change current path cd "$(dirname "${SCRIPT_PATH}")" out_dir="$(pwd)/results/${DD_DOMAIN}_${tc}_${duration}" if [ -f "${USERS_FILE}" ]; then cat "${USERS_FILE}" > dd-stress-test.users.csv else printf "ERROR: missing file\t%s\n\n" "${USERS_FILE}" >> /dev/stderr help_users_file >> /dev/stderr exit 2 fi if [ -f "${DOCS_FILE}" ]; then cat "${DOCS_FILE}" > dd-stress-test.docs.csv else cat > dd-stress-test.docs.csv <<-EOF /,Readme.md /,template.docx /,template_1.docx EOF fi JMETER="${JMETER:-${JMETER_DEFAULT}}" # Ensure JMeter is available / bootstrap it if [ ! -f "${JMETER}" ]; then echo "INFO: Could not find JMeter, attempting to download it" >> /dev/stderr curl -L 'https://dlcdn.apache.org//jmeter/binaries/apache-jmeter-5.5.tgz' | tar -xz JMETER="${JMETER_DEFAULT}" fi if [ ! -f "${JMETER}" ]; then printf "ERROR: missing JMeter\t%s\n\n" "${JMETER}" >> /dev/stderr fi # Ensure JMeter plugins are available / bootstrap them JMETER_PLUGINS="$(dirname "${JMETER}")/../lib/ext/jmeter-plugins-manager-1.8.jar" if [ ! -f "${JMETER_PLUGINS}" ]; then echo "INFO: Could not find JMeter plugins, attempting to download them" >> /dev/stderr curl -L 'https://jmeter-plugins.org/get/' > "${JMETER_PLUGINS}" fi if [ ! -f "${JMETER_PLUGINS}" ]; then printf "ERROR: missing JMeter plugins\t%s\n\n" "${JMETER_PLUGINS}" >> /dev/stderr fi if [ ! -f "${JMETER}" ] || [ ! -f "${JMETER_PLUGINS}" ]; then help_jmeter >> /dev/stderr exit 3 fi # Clean up out dir rm -rf "${out_dir}" mkdir -p "${out_dir}" # Adapt template sed -E \ -e "s%([^>]*)>(.*)<\!-- TC.*$%\\1>${tc} <\!-- TC -->%" \ -e "s%([^>]*)>(.*)<\!-- DURATION.*$%\\1>${duration} <\!-- DURATION -->%" \ -e "s/DD_DOMAIN/${DD_DOMAIN}/g" \ dd-stress-test.tpl.jmx > dd-stress-test.jmx # Call Selenium test process in parallel if [ "${USE_SELENIUM}" = "YES" ]; then printf "\n\nRunning parallel Selenium-based tests:\t%s\tover %s seconds\n\n" "${DD_DOMAIN}" "${duration}" python3 dd-test-selenium.py test --duration "${duration}" --out-dir "${out_dir}/selenium" "${DD_DOMAIN}" 2>&1 > "${out_dir}/selenium.log" & fi # Execute test printf "\n\nAbout to test:\t%s\twith %s 'users' over %s seconds\n\n" \ "${DD_DOMAIN}" "${tc}" "${duration}" env HEAP="-Xms2g -Xmx2g -XX:MaxMetaspaceSize=2g" "${JMETER}" -n -t dd-stress-test.jmx -l "${out_dir}/results" -e -o "${out_dir}/html" mv jmeter.log "${out_dir}/log" # Notify results printf "\n\nYou can find the results at:\t%s\n\n" "${out_dir}"