| #!/bin/bash |
| |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| # Function to get the git branch and commit hash |
| function get_git_info() { |
| local git_info |
| git_info=$(git log -1 --pretty=format:"%h") |
| local git_branch |
| git_branch=$(git rev-parse --abbrev-ref HEAD) |
| echo "${git_branch}_${git_info}" |
| } |
| |
| # OS detection |
| OS=$(uname -s) |
| |
| # Function to check if process exists - OS specific implementations |
| function process_exists() { |
| local check_pid=$1 |
| if [ "$OS" = "Darwin" ]; then |
| ps -p "${check_pid}" >/dev/null |
| else |
| [[ -e /proc/${check_pid} ]] |
| fi |
| } |
| |
| # Function to send signal to process - OS specific implementations |
| function send_signal_to_pid() { |
| local target_pid=$1 |
| local signal=$2 |
| if [ "$OS" = "Darwin" ]; then |
| kill "-${signal}" "${target_pid}" |
| else |
| kill -s "${signal}" "${target_pid}" |
| fi |
| } |
| |
| # Function to wait for a process with specific name to exit |
| function wait_for_process() { |
| local process_name=$1 |
| local timeout=$2 |
| local start_time |
| start_time=$(date +%s) |
| local end_time=$((start_time + timeout)) |
| local continue_outer_loop=false |
| |
| while [[ $(date +%s) -lt ${end_time} ]]; do |
| continue_outer_loop=false |
| local proc_pid |
| for proc_pid in $(pgrep -x "${process_name}"); do |
| if process_exists "${proc_pid}"; then |
| sleep 0.1 |
| continue_outer_loop=true |
| break |
| fi |
| done |
| [[ $continue_outer_loop == true ]] && continue |
| return 0 |
| done |
| |
| echo "Timeout waiting for process ${process_name} to exit." |
| return 1 |
| } |
| |
| # Function to wait for a process with specific PID to exit |
| function wait_for_process_pid() { |
| local wait_pid=$1 |
| local timeout=$2 |
| local start_time |
| start_time=$(date +%s) |
| local end_time=$((start_time + timeout)) |
| |
| while [[ $(date +%s) -lt ${end_time} ]]; do |
| if ! process_exists "${wait_pid}"; then |
| return 0 |
| fi |
| sleep 0.1 |
| done |
| |
| echo "Timeout waiting for process with PID ${wait_pid} to exit." |
| return 1 |
| } |
| |
| # Function to send a signal to a process |
| function send_signal() { |
| local process_name=$1 |
| local pids |
| pids=$(pgrep -x "${process_name}") || true |
| local signal=$2 |
| |
| if [[ -n "${pids}" ]]; then |
| local proc_pid |
| for proc_pid in ${pids}; do |
| if process_exists "${proc_pid}"; then |
| send_signal_to_pid "${proc_pid}" "${signal}" |
| fi |
| done |
| fi |
| } |
| |
| # Function to exit with error if a process with the given PID is running |
| exit_if_process_is_not_running() { |
| local check_pid="$1" |
| |
| if kill -0 "$check_pid" 2>/dev/null; then |
| echo "Process with PID $check_pid is running." |
| return 0 |
| else |
| echo "Error: Process with PID $check_pid is not running." |
| exit 1 |
| fi |
| } |
| |
| # Exit hook for profile.sh |
| function on_exit_profile() { |
| # Gracefully stop the server |
| send_signal "iggy-server" "KILL" |
| send_signal "iggy-bench" "KILL" |
| send_signal "flamegraph" "KILL" |
| send_signal "perf" "KILL" |
| } |
| |
| # Exit hook for run-benches.sh |
| function on_exit_bench() { |
| send_signal "iggy-server" "KILL" |
| # Use exact match for iggy-bench to avoid killing iggy-bench-dashboard |
| pids=$(pgrep -x "iggy-bench") || true |
| if [[ -n "${pids}" ]]; then |
| local bench_pid |
| for bench_pid in ${pids}; do |
| if process_exists "${bench_pid}"; then |
| send_signal_to_pid "${bench_pid}" "KILL" |
| fi |
| done |
| fi |
| } |
| |
| # --------------------------------------------------------------------------- |
| # Server lifecycle helpers for example-runner scripts |
| # --------------------------------------------------------------------------- |
| |
| readonly EXAMPLES_LOG_FILE="iggy-server.log" |
| readonly EXAMPLES_PID_FILE="iggy-server.pid" |
| readonly EXAMPLES_SERVER_TIMEOUT=300 |
| readonly EXAMPLES_STOP_TIMEOUT=5 |
| |
| # Resolve and validate the server binary path. |
| # Usage: resolve_server_binary [target] |
| # Sets global SERVER_BIN. |
| function resolve_server_binary() { |
| local target="${1:-}" |
| if [ -n "${target}" ]; then |
| SERVER_BIN="target/${target}/debug/iggy-server" |
| else |
| SERVER_BIN="target/debug/iggy-server" |
| fi |
| |
| if [ ! -f "${SERVER_BIN}" ]; then |
| echo "Error: Server binary not found at ${SERVER_BIN}" |
| echo "Please build the server binary before running this script:" |
| if [ -n "${target}" ]; then |
| echo " cargo build --target ${target} --bin iggy-server" |
| else |
| echo " cargo build --bin iggy-server" |
| fi |
| exit 1 |
| fi |
| echo "Using server binary at ${SERVER_BIN}" |
| } |
| |
| # Resolve and validate the CLI binary path. |
| # Usage: resolve_cli_binary [target] |
| # Sets global CLI_BIN. |
| function resolve_cli_binary() { |
| local target="${1:-}" |
| if [ -n "${target}" ]; then |
| CLI_BIN="target/${target}/debug/iggy" |
| else |
| CLI_BIN="target/debug/iggy" |
| fi |
| |
| if [ ! -f "${CLI_BIN}" ]; then |
| echo "Error: CLI binary not found at ${CLI_BIN}" |
| echo "Please build the CLI and examples before running this script:" |
| if [ -n "${target}" ]; then |
| echo " cargo build --target ${target} --bin iggy --examples" |
| else |
| echo " cargo build --bin iggy --examples" |
| fi |
| exit 1 |
| fi |
| echo "Using CLI binary at ${CLI_BIN}" |
| } |
| |
| # Remove old server data, log, and PID files. |
| function cleanup_server_state() { |
| rm -fr local_data |
| rm -f "${EXAMPLES_LOG_FILE}" "${EXAMPLES_PID_FILE}" |
| } |
| |
| # Start the plain (non-TLS) iggy server in background. |
| # Usage: start_plain_server [extra_args...] |
| function start_plain_server() { |
| echo "Starting server from ${SERVER_BIN}..." |
| IGGY_ROOT_USERNAME=iggy IGGY_ROOT_PASSWORD=iggy \ |
| ${SERVER_BIN} "$@" &>"${EXAMPLES_LOG_FILE}" & |
| echo $! >"${EXAMPLES_PID_FILE}" |
| } |
| |
| # Start the TLS-enabled iggy server in background. |
| # Usage: start_tls_server [extra_args...] |
| function start_tls_server() { |
| echo "Starting TLS server from ${SERVER_BIN}..." |
| IGGY_ROOT_USERNAME=iggy IGGY_ROOT_PASSWORD=iggy \ |
| IGGY_TCP_TLS_ENABLED=true \ |
| IGGY_TCP_TLS_CERT_FILE=core/certs/iggy_cert.pem \ |
| IGGY_TCP_TLS_KEY_FILE=core/certs/iggy_key.pem \ |
| ${SERVER_BIN} "$@" &>"${EXAMPLES_LOG_FILE}" & |
| echo $! >"${EXAMPLES_PID_FILE}" |
| } |
| |
| # Block until "has started" appears in the server log or timeout. |
| # Usage: wait_for_server_ready [label] |
| function wait_for_server_ready() { |
| local label="${1:-Iggy}" |
| local elapsed=0 |
| while ! grep -q "has started" "${EXAMPLES_LOG_FILE}"; do |
| if [ ${elapsed} -gt ${EXAMPLES_SERVER_TIMEOUT} ]; then |
| echo "${label} server did not start within ${EXAMPLES_SERVER_TIMEOUT} seconds." |
| ps fx 2>/dev/null || ps aux |
| cat "${EXAMPLES_LOG_FILE}" |
| exit 1 |
| fi |
| echo "Waiting for ${label} server to start... ${elapsed}" |
| sleep 1 |
| ((elapsed += 1)) |
| done |
| } |
| |
| # Gracefully stop the server: SIGTERM, wait up to EXAMPLES_STOP_TIMEOUT |
| # seconds for exit, then SIGKILL if still alive. |
| function stop_server() { |
| if [ ! -e "${EXAMPLES_PID_FILE}" ]; then |
| return |
| fi |
| local pid |
| pid="$(cat "${EXAMPLES_PID_FILE}")" |
| rm -f "${EXAMPLES_PID_FILE}" |
| |
| kill -TERM "${pid}" 2>/dev/null || true |
| |
| if wait_for_process_pid "${pid}" "${EXAMPLES_STOP_TIMEOUT}" 2>/dev/null; then |
| return |
| fi |
| |
| echo "Server PID ${pid} did not exit after ${EXAMPLES_STOP_TIMEOUT}s, sending SIGKILL..." |
| kill -KILL "${pid}" 2>/dev/null || true |
| wait_for_process_pid "${pid}" 2 2>/dev/null || true |
| } |
| |
| # Print final result and dump the log on failure. |
| function report_result() { |
| local exit_code=$1 |
| if [ "${exit_code}" -eq 0 ]; then |
| echo "Test passed" |
| else |
| echo "Test failed, see log file:" |
| test -e "${EXAMPLES_LOG_FILE}" && cat "${EXAMPLES_LOG_FILE}" |
| fi |
| rm -f "${EXAMPLES_LOG_FILE}" "${EXAMPLES_PID_FILE}" |
| } |
| |
| # Portable timeout wrapper (macOS has gtimeout via coreutils, Linux has timeout). |
| function portable_timeout() { |
| local secs="$1" |
| shift |
| if command -v timeout >/dev/null 2>&1; then |
| timeout "${secs}" "$@" |
| elif command -v gtimeout >/dev/null 2>&1; then |
| gtimeout "${secs}" "$@" |
| else |
| "$@" |
| fi |
| } |
| |
| # Run commands extracted from a README file. |
| # Usage: run_readme_commands readme_file grep_pattern [cmd_timeout [grep_exclude]] |
| # Reads matching lines, strips backticks/comments, executes each. |
| # Calls TRANSFORM_COMMAND function on each command if defined. |
| # Returns: sets global EXAMPLES_EXIT_CODE. |
| function run_readme_commands() { |
| local readme_file="$1" |
| local grep_pattern="$2" |
| local cmd_timeout="${3:-0}" |
| local grep_exclude="${4:-}" |
| |
| if [ ! -f "${readme_file}" ]; then |
| return |
| fi |
| |
| local commands |
| commands=$(grep -E "${grep_pattern}" "${readme_file}" || true) |
| if [ -n "${grep_exclude}" ]; then |
| commands=$(echo "${commands}" | grep -v "${grep_exclude}" || true) |
| fi |
| if [ -z "${commands}" ]; then |
| return |
| fi |
| |
| while IFS= read -r command; do |
| command=$(echo "${command}" | tr -d '`' | sed 's/^#.*//') |
| if [ -z "${command}" ]; then |
| continue |
| fi |
| |
| if declare -f TRANSFORM_COMMAND >/dev/null 2>&1; then |
| command=$(TRANSFORM_COMMAND "${command}") |
| fi |
| |
| echo -e "\e[33mChecking command from ${readme_file}:\e[0m ${command}" |
| echo "" |
| |
| set +e |
| if [ "${cmd_timeout}" -gt 0 ] 2>/dev/null; then |
| eval "portable_timeout ${cmd_timeout} ${command}" |
| local test_exit_code=$? |
| if [[ ${test_exit_code} -ne 0 && ${test_exit_code} -ne 124 ]]; then |
| EXAMPLES_EXIT_CODE=${test_exit_code} |
| fi |
| else |
| eval "${command}" |
| EXAMPLES_EXIT_CODE=$? |
| fi |
| set -e |
| |
| if [ "${EXAMPLES_EXIT_CODE}" -ne 0 ]; then |
| echo "" |
| echo -e "\e[31mCommand failed:\e[0m ${command}" |
| echo "" |
| return |
| fi |
| |
| sleep 2 |
| done <<< "${commands}" |
| } |