diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index f1ac8782f..e6b15b8eb 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -109,28 +109,65 @@ Code coverage is monitored for every PR and for the code base as a whole using [ ### Running the Tests +There are several ways to run the tests locally: + +#### 1. Using Composer Scripts (Recommended) + +The simplest way to run tests is using the Composer scripts: + +```bash +# Run tests without coverage +composer test + +# Run tests with coverage +composer coverage + +# Run tests with automatic test server management +composer test:withserver +``` + +#### 2. Manual Test Environment Management + +If you need more control over the test environment, you can manage it manually: + +```bash +# Start all test servers and set environment variables +# We need to source the script to properly set environment variables in our shell +source scripts/start-test-environment.sh + +# Now run your tests +composer test + +# When done, stop all servers +./scripts/stop-test-environment.sh +``` + +Note: The environment scripts must be sourced (using `source` or `.`) to properly set environment variables in your shell. + +#### 3. Individual Component Control + +For debugging or development, you might want to manage individual components: + ```bash -# Start the test server +# Just the test server PORT=8080 vendor/bin/start.sh -export "REQUESTS_TEST_HOST_HTTP=localhost:8080" +export REQUESTS_TEST_HOST_HTTP=localhost:8080 -# Start the proxy server +# Just the proxy servers PORT=9002 tests/utils/proxy/start.sh PORT=9003 AUTH="test:pass" tests/utils/proxy/start.sh -export "REQUESTS_HTTP_PROXY=localhost:9002" -export "REQUESTS_HTTP_PROXY_AUTH=localhost:9003" -export "REQUESTS_HTTP_PROXY_AUTH_USER=test" -export "REQUESTS_HTTP_PROXY_AUTH_PASS=pass" +export REQUESTS_HTTP_PROXY=localhost:9002 +export REQUESTS_HTTP_PROXY_AUTH=localhost:9003 +export REQUESTS_HTTP_PROXY_AUTH_USER=test +export REQUESTS_HTTP_PROXY_AUTH_PASS=pass +``` -# Run the tests -composer test +Remember to stop any servers you start: -# Stop the proxy server -PORT=9002 tests/utils/proxy/stop.sh +```bash +vendor/bin/stop.sh # Stop test server +PORT=9002 tests/utils/proxy/stop.sh # Stop proxy servers PORT=9003 tests/utils/proxy/stop.sh - -# Stop the test server -vendor/bin/stop.sh ``` To run the test with code coverage, use `composer coverage` instead. diff --git a/.gitignore b/.gitignore index 8f4479dd1..bb57d438f 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ certificates/etag-*.txt # Ignore temporary files generated by the testing proxy. tests/utils/proxy/__pycache__ tests/utils/proxy/*.pid +tests/utils/pids diff --git a/composer.json b/composer.json index 94269ca4c..ddc886b7d 100644 --- a/composer.json +++ b/composer.json @@ -87,25 +87,29 @@ "@php ./vendor/squizlabs/php_codesniffer/bin/phpcbf" ], "test": [ - "@php ./vendor/phpunit/phpunit/phpunit --no-coverage" - ], - "test10": [ - "@php ./vendor/phpunit/phpunit/phpunit -c phpunit10.xml.dist --no-coverage" + "./scripts/run-phpunit.sh --no-coverage" ], "coverage": [ - "@php ./vendor/phpunit/phpunit/phpunit" + "./scripts/run-phpunit.sh" + ], + "testserver:start": [ + "./scripts/start-test-environment.sh" + ], + "testserver:stop": [ + "./scripts/stop-test-environment.sh" ], - "coverage10": [ - "@php ./vendor/phpunit/phpunit/phpunit -c phpunit10.xml.dist" + "test:withserver": [ + "./scripts/run-tests-with-server.sh" ] }, "scripts-descriptions": { "lint": "Lint PHP files to find parse errors.", "checkcs": "Check the entire codebase for code-style issues.", "fixcs": "Fix all auto-fixable code-style issues in the entire codebase.", - "test": "Run the unit tests on PHPUnit 5.x - 9.x without code coverage.", - "test10": "Run the unit tests on PHPUnit 10.x without code coverage.", - "coverage": "Run the unit tests on PHPUnit 5.x - 9.x with code coverage.", - "coverage10": "Run the unit tests on PHPUnit 10.x with code coverage." + "test": "Run the unit tests without code coverage (auto-detects PHPUnit version)", + "coverage": "Run the unit tests with code coverage (auto-detects PHPUnit version)", + "testserver:start": "Start the test environment including test server and proxy servers (Note: environment variables will only be available in a sourced shell)", + "testserver:stop": "Stop all running test environment servers", + "test:withserver": "Start test servers, run PHPUnit tests with appropriate config, then stop servers" } } diff --git a/scripts/run-phpunit.sh b/scripts/run-phpunit.sh new file mode 100755 index 000000000..adb303588 --- /dev/null +++ b/scripts/run-phpunit.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +# Try to determine script location +if [ -n "${BASH_SOURCE:-}" ]; then + # Bash-specific path resolution + SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +else + # POSIX fallback - assume we're in the repository root + PROJECT_ROOT="$(pwd)" + SCRIPT_DIR="$PROJECT_ROOT/scripts" +fi + +# Detect PHPUnit version +PHPUNIT_VERSION=$("${PROJECT_ROOT}/vendor/bin/phpunit" --version | grep -oE '[0-9]+\.[0-9]+' | head -n1) + +# Determine if we should include coverage based on argument +COVERAGE_ARG="" +if [ "$1" != "--no-coverage" ]; then + COVERAGE_ARG="--coverage-html build/coverage" +fi + +# Run the tests with the appropriate config +if printf '%s\n%s\n' "10.0" "$PHPUNIT_VERSION" | sort -V -C 2>/dev/null; then + "${PROJECT_ROOT}/vendor/bin/phpunit" -c phpunit10.xml.dist $COVERAGE_ARG +else + "${PROJECT_ROOT}/vendor/bin/phpunit" $COVERAGE_ARG +fi diff --git a/scripts/run-tests-with-server.sh b/scripts/run-tests-with-server.sh new file mode 100755 index 000000000..232ecd2aa --- /dev/null +++ b/scripts/run-tests-with-server.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +# Try to determine script location +if [ -n "${BASH_SOURCE:-}" ]; then + # Bash-specific path resolution + SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +else + # POSIX fallback - assume we're in the repository root + PROJECT_ROOT="$(pwd)" + SCRIPT_DIR="$PROJECT_ROOT/scripts" +fi + +# Source the environment setup +if ! . "${SCRIPT_DIR}/start-test-environment.sh"; then + exit 1 +fi + +# Run the tests +"${SCRIPT_DIR}/run-phpunit.sh" --no-coverage +TEST_EXIT_CODE=$? + +# Stop the test environment +. "${SCRIPT_DIR}/stop-test-environment.sh" + +exit $TEST_EXIT_CODE diff --git a/scripts/start-test-environment.sh b/scripts/start-test-environment.sh new file mode 100755 index 000000000..dfe3e80f8 --- /dev/null +++ b/scripts/start-test-environment.sh @@ -0,0 +1,120 @@ +#!/bin/sh + +# Try to determine script location +if [ -n "${BASH_SOURCE:-}" ]; then + # Bash-specific path resolution + SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +else + # POSIX fallback - assume we're in the repository root + PROJECT_ROOT="$(pwd)" + SCRIPT_DIR="$PROJECT_ROOT/scripts" +fi + +# Detect if we're being sourced (POSIX-compatible way) +sourced=0 +if [ -n "$ZSH_EVAL_CONTEXT" ]; then + case $ZSH_EVAL_CONTEXT in *:file:*) sourced=1;; esac +elif [ -n "$KSH_VERSION" ]; then + [ "$(cd $(dirname -- $0) && pwd -P)/$(basename -- $0)" != "$(cd $(dirname -- ${.sh.file}) && pwd -P)/$(basename -- ${.sh.file})" ] && sourced=1 +elif [ -n "$BASH_VERSION" ]; then + (return 0 2>/dev/null) && sourced=1 +else + # POSIX fallback - check if we can modify our environment + # Try to modify a test variable + TEST_VAR="test" + if [ -z "${TEST_VAR:-}" ]; then + sourced=0 + else + sourced=1 + fi +fi + +if [ $sourced -eq 0 ]; then + echo "Warning: This script should be sourced to set environment variables" + echo "Please either:" + echo "1. Source this script: source scripts/start-test-environment.sh" + echo "2. Or manually set these environment variables:" + echo " export REQUESTS_TEST_HOST_HTTP=localhost:8080" + echo " export REQUESTS_HTTP_PROXY=localhost:9002" + echo " export REQUESTS_HTTP_PROXY_AUTH=localhost:9003" + echo " export REQUESTS_HTTP_PROXY_AUTH_USER=test" + echo " export REQUESTS_HTTP_PROXY_AUTH_PASS=pass" + if [ -n "${BASH_VERSION:-}" ]; then + exit 1 + fi +fi + +PID_DIR="${PROJECT_ROOT}/tests/utils/pids" + +# Check if mitmproxy is installed +if ! command -v mitmdump >/dev/null 2>&1; then + echo "Error: mitmproxy is not installed. Please install it with: pip3 install mitmproxy" + return 1 2>/dev/null || exit 1 +fi + +# Get mitmproxy version and compare with minimum required +MITM_VERSION=$(mitmdump --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1) +MINIMUM_VERSION="11.0.2" + +# POSIX-compatible version comparison +if ! printf '%s\n%s\n' "$MINIMUM_VERSION" "$MITM_VERSION" | sort -V -C 2>/dev/null; then + echo "Error: mitmproxy version $MITM_VERSION is too old" + echo "Please upgrade to version $MINIMUM_VERSION or newer with: pip3 install --upgrade mitmproxy" + return 1 2>/dev/null || exit 1 +fi + +echo "Found mitmproxy version $MITM_VERSION" + +# Create directory for PID files if it doesn't exist +mkdir -p "$PID_DIR" + +# Start the test server +echo "Starting test server..." +PORT=8080 "${PROJECT_ROOT}/vendor/bin/start.sh" +echo $! > "${PID_DIR}/test-server.pid" +REQUESTS_TEST_HOST_HTTP=localhost:8080 +export REQUESTS_TEST_HOST_HTTP + +# Start proxy servers +echo "Starting proxy servers..." +PORT=9002 "${PROJECT_ROOT}/tests/utils/proxy/start.sh" +echo $! > "${PID_DIR}/proxy-server.pid" + +PORT=9003 AUTH="test:pass" "${PROJECT_ROOT}/tests/utils/proxy/start.sh" +echo $! > "${PID_DIR}/proxy-auth-server.pid" + +# Set environment variables +REQUESTS_HTTP_PROXY=localhost:9002 +REQUESTS_HTTP_PROXY_AUTH=localhost:9003 +REQUESTS_HTTP_PROXY_AUTH_USER=test +REQUESTS_HTTP_PROXY_AUTH_PASS=pass + +export REQUESTS_HTTP_PROXY +export REQUESTS_HTTP_PROXY_AUTH +export REQUESTS_HTTP_PROXY_AUTH_USER +export REQUESTS_HTTP_PROXY_AUTH_PASS + +# Wait for servers to be ready +echo "Waiting for servers to be ready..." +sleep 2 + +# Test server connections +echo "Testing server connections..." +if ! curl -s -I http://localhost:8080 >/dev/null 2>&1; then + echo "Test server not responding" + return 1 2>/dev/null || exit 1 +fi + +if ! curl -s -I http://localhost:9002 >/dev/null 2>&1; then + echo "Proxy server not responding" + return 1 2>/dev/null || exit 1 +fi + +echo "Test environment is ready!" +echo "Environment variables set:" +echo "REQUESTS_TEST_HOST_HTTP=localhost:8080" +echo "REQUESTS_HTTP_PROXY=localhost:9002" +echo "REQUESTS_HTTP_PROXY_AUTH=localhost:9003" + +return 0 2>/dev/null || exit 0 diff --git a/scripts/stop-test-environment.sh b/scripts/stop-test-environment.sh new file mode 100755 index 000000000..b00c631a0 --- /dev/null +++ b/scripts/stop-test-environment.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +# Try to determine script location +if [ -n "${BASH_SOURCE:-}" ]; then + # Bash-specific path resolution + SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +else + # POSIX fallback - assume we're in the repository root + PROJECT_ROOT="$(pwd)" + SCRIPT_DIR="$PROJECT_ROOT/scripts" +fi + +PID_DIR="${PROJECT_ROOT}/tests/utils/pids" + +# Function to safely kill a process +kill_process() { + pid_file="$1" + if [ -f "$pid_file" ]; then + pid=$(cat "$pid_file") + if kill -0 "$pid" 2>/dev/null; then + echo "Stopping process $pid" + kill "$pid" + rm "$pid_file" + else + echo "Process $pid not running" + rm "$pid_file" + fi + fi +} + +# Stop all servers +echo "Stopping test environment..." + +# Stop test server +kill_process "${PID_DIR}/test-server.pid" +"${PROJECT_ROOT}/vendor/bin/stop.sh" + +# Stop proxy servers +PORT=9002 "${PROJECT_ROOT}/tests/utils/proxy/stop.sh" +kill_process "${PID_DIR}/proxy-server.pid" + +PORT=9003 "${PROJECT_ROOT}/tests/utils/proxy/stop.sh" +kill_process "${PID_DIR}/proxy-auth-server.pid" + +# Clean up PID directory if empty +rmdir "${PID_DIR}" 2>/dev/null || true + +echo "Test environment stopped" + +return 0 2>/dev/null || exit 0